【java+selenium】⽹易云⾳乐刷累计听歌数
背景
应该是在去年的时候,刷知乎看到⼀个问题,⼤概是说怎么刷⽹易云⾳乐个⼈累计听歌数,然后有⼀个⾼赞回答,贴了⼀段js代码,直接在浏览器console执⾏就可以了。当时试了下,直接⼀下⼦刷了有好⼏万。悲剧的是,第⼆天⼜回到原来的样⼦了,很明显这种⽅式被⽹易云⾳乐发现封掉了。⽽且后续⽹易云还针对累计听歌数加了⼀些限制,每天最多增加300⾸。今天带来⼀种通过java+selenium的⽅式,⾃动播放歌曲,来达到刷累计听歌数的效果。另外借助这个demo,对selenium的使⽤更加熟悉,也算是爬⾍应⽤中⼀些有趣的东西了。
思路
登录,有以下两种⽅式可以选择:
a. 模拟web端的登录过程。优点:这种⽅式更加通⽤,便于动态切换账号。缺点:⽐直接使⽤cookie稍微⿇烦⼀些,并且有⼀定⼏率
会出现图形验证码,需要考虑这种情况。
b. 设置cookie。优点:不⽤处理登录过程,⽐较简单⽅便,在cookie的过期时间⽐较长情况下还是⽐较⽅便的,不⽤频繁切换。缺
点:切换账号⽐较⿇烦,不能达到⾃动化。我这⾥选择的该⽅式。
播放:上⼀个步骤中登录成功后,直接打开歌单列表页⾯。如下图,在歌单列表页⾯可以看到。有3个地⽅是可以点击播放的,我最先想到是最下⾯⼀个播放按钮,然后⼀直保持底部播放组件的显⽰,实时获取播放的动态。尝试通过模拟点击播放按钮,始终不成功,最终点击最上⾯的播放按钮可以播放的。
获取播放动态:为了确定播放是否在正常进⾏,可以通过实时获取个⼈home页⾯的累计听歌数相关信息,⽤于监控,由于已经有⼀个页⾯在播放歌曲了,为了不影响原有播放歌曲的页⾯,可以打开⼀个新的tab页来获取个⼈home页⾯,打开新的table页,这⾥采⽤js 的⽅式window.open('about:blank')。最终都会看到如下类似如下格式⽇志,那就说明成功了:
2019-03-26 09:25:10,406 INFO [,main] - [com.github.wycm.Music163] - 伊犁河畔-00:00 / 00:00---当前播放第1⾸歌曲, 累计听歌:20572
2019-03-26 09:25:16,817 INFO [,main] - [com.github.wycm.Music163] - 伊犁河畔-01:00 / 07:19---当前播放第1⾸歌曲, 累计听歌:20572
2019-03-26 09:25:23,157 INFO [,main] - [com.github.wycm.Music163] - 伊犁河畔-01:06 / 07:19---当前播放第1⾸歌曲, 累计听歌:20572
2019-03-26 09:25:29,394 INFO [,main] - [com.github.wycm.Music163] - 伊犁河畔-01:13 / 07:19---当前播放第1⾸歌曲, 累计听歌:20572
2019-03-26 09:25:35,592 INFO [,main] - [com.github.wycm.Music163] - 伊犁河畔-01:19 / 07:19---当前播放第1⾸歌曲, 累计听歌:20572
2019-03-26 09:25:41,974 INFO [,main] - [com.github.wycm.Music163] - 伊犁河畔-01:25 / 07:19---当前播放第1⾸歌曲, 累计听歌:20572
完整代码
package com.github.wycm;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import urrent.TimeUnit;
import Matcher;
import Pattern;
/**
* Created by wycm
*/
public class Music163 {
private static Logger logger = Logger(Music163.class);
/
/拷贝登录成功的浏览器原始cookie
private final static String RAW_COOKIES = "cookie1=value1; cookie2=value2";
private final static String CHROME_DRIVER_PATH = "/Users/wangyang/Downloads/chromedriver";
//歌曲列表id
private static String startId = "22336453";
private static String userId = null;
private static Set<String> playListSet = new HashSet<>();
private static Pattern pattern = Patternpile("<span class=\"j-flag time\"><em>(.*?)</em>(.*?)</span>");
private static Pattern songName = Patternpile("class=\"f-thide name fc1 f-fl\" title=\"(.*?)\"");
private static ChromeOptions chromeOptions = new ChromeOptions();
private static WebDriver driver = null;
static {
System.setProperty("webdriver.chrome.driver", CHROME_DRIVER_PATH);
chromeOptions.addArguments("--no-sandbox");
}
public static void main(String[] args) throws InterruptedException {
while (true){
try {
driver = new ChromeDriver(chromeOptions);
playListSet.add(startId);
invoke();
} catch (Exception e){
<(e.getMessage(), e);
} finally {
driver.quit();
}
Thread.sleep(1000 * 10);
}
}
/**
* 初始化cookies
*/
private static void initCookies(){
Arrays.stream(RAW_COOKIES.split("; ")).forEach(rawCookie -> {
String[] ss = rawCookie.split("=");
Cookie cookie = new Cookie.Builder(ss[0], ss[1]).domain(".163").build();
driver.manage().addCookie(cookie);
});
}
private static void invoke() throws InterruptedException {
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.manage().timeouts().pageLoadTimeout(15, TimeUnit.SECONDS);
String s = null;
<("music.163/");
initCookies();
<("music.163/");
s = PageSource();
userId = group(s, "userId:(\\d+)", 1);
<("music.163/#/playlist?id=" + startId);
driver.switchTo().frame("contentFrame");
WebElement element = driver.findElement(By.cssSelector("[id=content-operation]>a:first-child"));
element.click();
((JavascriptExecutor) driver).executeScript("window.open('about:blank')");
ArrayList<String> tabs = new ArrayList<String>(WindowHandles());
driver.switchTo().(0));
driver.switchTo().defaultContent();
int i = 0;
String lastSongName = "";
int count = 0;
while (true){
if(i > Integer.MAX_VALUE - 2){
break;
}
i++;
s = PageSource();
driver.switchTo().(1)); //switches to new tab
String songs = null;
try{
<("music.163/user/home?id=" + userId);
driver.switchTo().frame("contentFrame");
songs = PageSource(), "累积听歌(\\d+)⾸", 1);
} catch (TimeoutException e){
<(e.getMessage(), e);
}
driver.switchTo().(0));
Matcher matcher = pattern.matcher(s);
selenium获取cookie
Matcher songNameMatcher = songName.matcher(s);
if (matcher.find() && songNameMatcher.find()){
String songNameStr = up(1);
if (!songNameStr.equals(lastSongName)){
count++;
lastSongName = songNameStr;
}
logger.info(songNameStr + "-" + up(1) + up(2) + "---当前播放第" + count + "⾸歌曲, 累计听歌:" + songs);            } else {
logger.info("解析歌曲播放记录或歌曲名失败");
}
Thread.sleep(1000 * 30);
}
}
public static String group(String str, String regex, int index) {
Pattern pattern = Patternpile(regex);
Matcher matcher = pattern.matcher(str);
return matcher.find() ? up(index) : "";
}
}
运⾏注意事项
修改⾃⼰相关chromedriver路径配置
登录⾃⼰的web端⽹易云⾳乐:
复制⾃⼰登录成功的原始cookies,⾄代码中的RAW_COOKIES字段
切换歌单,如果默认的歌单播放完成后,可以搜索⼀些没有播放过的歌单,类似music.163/#/playlist?id=22336453的url,提取出id,直接替换代码中的startId字段。
总结
⼤家可能会有疑问,我想把这个任务放到⾃⼰的服务器上直接后台运⾏。这就是服务器上搭建selenium运⾏环境的问题了,可以参考我上⼀篇⽂章。阿⾥云和腾讯云最低配的服务器都能够跑起来的。
另外这⾥为啥采⽤selenium的⽅式,有没有其他更简单的⽅式,直接通过简单的Http请求的⽅式达到刷的效果。我个⼈尝试过像通过纯http 请求的⽅式,到增加个⼈累计听歌数的请求,由于⽹银云的请求都做了加密,最终没有到。所以就⽤selenium的⽅式来代替。
最后
完整⼯程代码见:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。