写在前面
在上篇文章关于webdriver基本知识已经写过,这篇是webdriver的实践篇。
上一篇可以参考:http://b1ue.cn/archives/56.html
其实知乎的图片爬虫没必要用webdriver来实现,因为知乎的每个答案是根据ajax请求去请求api,然后写在页面里的。
大致流程如下
访问页面 -> 预加载5个答案的JSON并写在页面 -> 滑动至底部 触发翻页api请求 -> 追加内容到页面
而且也没有什么明显的防爬机制,所以完全可以使用,请求接口的方式来爬图片。
我拦截了一个原始翻页请求:
https://www.zhihu.com/api/v4/questions/286837417/answers?include=data[*].is_normal,admin_closed_comment,reward_info,is_collapsed,annotation_action,annotation_detail,collapse_reason,is_sticky,collapsed_by,suggest_edit,comment_count,can_comment,content,editable_content,voteup_count,reshipment_settings,comment_permission,created_time,updated_time,review_info,relevant_info,question,excerpt,relationship.is_authorized,is_author,voting,is_thanked,is_nothelp,is_labeled;data[*].mark_infos[*].url;data[*].author.follower_count,badge[*].topics&limit=5&offset=5&platform=desktop&sort_by=default
简化一下
https://www.zhihu.com/api/v4/questions/286837417/answers?include=data[*].content&limit=5&offset=0&platform=desktop&sort_by=default
totals值为832
limit最大值为20
一点一点爬过去就ok了,不过这篇文章是写关于webdriver爬虫的,所以这些暂时和这篇文章没关系。
如何实现webdriver爬取所有图片
首先打开要爬的目标,比如:https://www.zhihu.com/question/286837417
打开页面后会默认展示5个回答,但这个提问里的回答远不止5个。
所以要让其他回答也展示出来,必须让他触发翻页请求,把下一页的内容追加到页面。
当滑动条滑到页面最底部时,就会触发翻页,所以只要一直把页面拉倒最下面就可以了。
通过代码实现
这里我先放上代码,通过上面的逻辑梳理,就能知道大致该怎么写了。
1.首先初始化webdriver
2.这里重写了一个队列类,实现了多线程,当启动线程时就会从队列里弹出一个对象去下载到本地。
3.访问要爬的页面
4.死循环,使其翻页(这里用js把页面拉倒最下面,再通过键盘上的DOWN实现触发翻页)
5.取出源码使用Jsoup解析(不习惯webdriver的原生方法,所以用Jsoup),取出noscript下的img标签里的src属性 也就是图片地址
6.添加到下载队列里
public class Zhihu {
static{
System.setProperty("webdriver.gecko.driver","C:\\Users\\xxx\\Downloads\\geckodriver-v0.23.0-win64\\geckodriver.exe");
FirefoxOptions options = new FirefoxOptions();
options.setBinary("D:\\Software\\Firefox\\firefox.exe");
driver = new FirefoxDriver(options);
}
private static FirefoxDriver driver;
public static void main(String[] args) throws InterruptedException {
DownloadQueue queue = new DownloadQueue(new File("c:/Users/xxx/Desktop/img/"));
driver.get("https://www.zhihu.com/question/286837417");
Thread thread = new Thread(queue);
thread.start();
while (true)
{
pageBottom();
String pageSource = driver.getPageSource();
Document parse = Jsoup.parse(pageSource);
Elements select = parse.select("noscript > img");
for (Element element : select) {
String src = element.attr("src");
queue.put(src);
}
System.out.println(queue.size());
}
}
public static void pageBottom(){
String next = "window.scrollTo(0,document.body.scrollHeight)";
driver.executeScript(next);
Actions action = new Actions(driver);
action.sendKeys(Keys.PAGE_UP).perform();
action.sendKeys(Keys.PAGE_DOWN).perform();
action.sendKeys(Keys.ARROW_DOWN).perform();
action.sendKeys(Keys.PAGE_DOWN).perform();
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class DownloadQueue extends LinkedBlockingQueue<String> implements Runnable{
private File path;
public DownloadQueue(File path) {
super(Integer.MAX_VALUE);
this.path = path;
}
public void run() {
while (true){
String poll = this.poll();
if (poll!=null){
try {
downloadPicture(poll);
} catch (Exception e) {
continue;
}
}
}
}
private void downloadPicture(String urlList) throws Exception{
URL url = null;
int imageNumber = 0;
url = new URL(urlList);
DataInputStream dataInputStream = new DataInputStream(url.openStream());
FileOutputStream fileOutputStream = new FileOutputStream(new File(path,String.valueOf(System.currentTimeMillis()).concat(".jpg")));
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = dataInputStream.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
byte[] context=output.toByteArray();
fileOutputStream.write(output.toByteArray());
dataInputStream.close();
fileOutputStream.close();
}
}
跑一下看看结果
当然也可以爬点别的,比如:https://www.zhihu.com/question/26297181/