Selenium Webdriver 爬知乎图片

写在前面

在上篇文章关于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();


    }
}

跑一下看看结果
1.png

当然也可以爬点别的,比如:https://www.zhihu.com/question/26297181/

2.png

发表留言

如未标注转载则文章均为本人原创,转载前先吱声,未授权转载我就锤爆你狗头。

人生在世,错别字在所难免,无需纠正。