Java爬虫-爬取知乎内容(附源码注释)

在前一段时间,做了一个demo,苦于没有数据展示,所以翻了很多关于爬虫的资料,在这里分享一下踩过的坑

踩过的坑

之前没接触爬虫的时候以为,只要请求中携带相关信息(请求头中跟浏览器发送的一模一样)就能获取到页面.

  • 例如,在请求中携带cookie
  • 伪装成浏览器.
  • 伪装referer
    请求跟浏览器中的请求没什么区别.然而,这种操作确实对大部分页面有效
    ,但是还有一小部分呢.
    直到某天, 我突然想到试着爬一下知乎,用之前的模拟请求的方式爬取了一下,点击运行,
    稍等片刻,~~誒~好多乱码啊,以为是编码的问题,然而,我把得到html数据写入到,html文件中,用浏览器打开之后还真是乱码.
    解决过程
    在经历了乱码的问题后,查阅了百度,原来知乎把数据并没有直接相应给客户端,而是,客户端拿到数据之后,还要经过js去解析一次,最后才得到我们所得到的页面
    ,之前的方式为什么乱码呢?就是因为只是发了请求,服务端响应了,但是页面中的js并没有执行, 这时候,页面当然不能正常显示.随着一次次的百度,发现这种情况可以使用无头浏览器进行爬取,其工作原理是: 通过java代码间接操作无头浏览器并且拿到浏览器页面中的内容.

使用到的工具

演示

在这里插入图片描述

  • 无头浏览器(此文中使用chrome作为无头浏览器)

  • selenium

  • 语言__Java jdk1.8

  • 项目使用maven构建

操作无头浏览器使用qq登录
把二维码保存到本地.(保存的时候请使用selenium的截图功能,或者保存功能.不要直接找到二维码的src进行请求下载,这样永远提示二维码过期,验证码同理)
java客户端使用scanner阻塞,等待确认扫描完成获取页面内容
手机扫描(二维码超时请重启客户端.)
java客户端输入任意内容获取页面内容
拿到页面并且解析
…接下来就可以进行你想要的操作了…

代码

源码下载链接

public static void main(String[] args) throws InterruptedException, IOException {
        long time = System.currentTimeMillis();
        // 可选,设定驱动目录,如果驱动和chrome安装目录,则不用设置
        //System.setProperty("webdriver.chrome.driver", "/usr/local/bin/chromedriver");
        //chrome配置项
        ChromeOptions chromeOptions = new ChromeOptions();
        //设置其为无头模式,无界面
//        chromeOptions.addArguments("--headless");
        //创建一个窗体(一个空页面)
        ChromeDriver driver = new ChromeDriver(chromeOptions);
        //连接到指定的网站
        driver.get("http://zhihu.com");

        //休眠1s,给js预留一定的执行时间

        //找到登录按钮并且点击
        List<WebElement> elementsByCssSelector = driver.findElementsByCssSelector("#root > div > main > div > div > div > div.SignContainer-inner > div.SignContainer-switch > span");
        elementsByCssSelector.get(0).click();


        //找到社交登录按钮并且点击
        WebElement contactLogin = driver.findElementByXPath("//*[@id=\"root\"]/div/main/div/div/div/div[2]/div[1]/form/div[5]/span[5]/button");
        contactLogin.click();

        //点击qq图标按钮并且点击,这时候会出现新窗体,需要切换到新窗体
        WebElement qqLogin = driver.findElementByXPath("//*[@id=\"root\"]/div/main/div/div/div/div[2]/div[1]/form/div[5]/span[5]/span/button[3]");
        qqLogin.click();

        //先把当前窗口的句柄保存起来,等会登录成功之后还需要跳转回来
        String home = driver.getWindowHandle();

        //获得窗口句柄集合,
        Set<String> windowHandles = driver.getWindowHandles();
        System.out.println(driver.getTitle());
        //遍历集合
        for (String windowHandle : windowHandles) {

            //如果窗口标题是QQ账号安全登录,我们切换到此窗口
            if ("QQ帐号安全登录".equals(driver.switchTo().window(windowHandle).getTitle())) {
                //在此处睡眠2s,以免网速慢导致二维码没有加载出来
                Thread.sleep(2000);
                //截图并且保存截图文件,默认路径是在C:\Users\{{用户名}}\AppData\Local\Temp
                File srcFile = driver.getScreenshotAs(OutputType.FILE);
                //把文件拷贝到自定义目录
                FileUtils.copyFile(srcFile, new File("E:/screenshot.png"));
                //拷贝完成删除默认路径的文件
                srcFile.delete();

                //在这阻塞一下,否则虽然截图了,但是还没有登录.
                Scanner sc = new Scanner(System.in);
                System.out.println("扫完二维码之后任意输入字符");
                sc.nextLine();

                //在扫描完成二维码之后,让其跳回主窗口
                driver.switchTo().window(home);
            }
        }
        //获取到首页的源码并将其解析成一个document对象
        String pageSource = driver.getPageSource();
        Document document = Jsoup.parse(pageSource);

        //遍历知乎首页的内容标题和其详细地址
        Elements select = document.select("#TopstoryContent .ContentItem h2 a");
        for (Element element : select) {
            System.out.print(element.text());
            System.out.print(element.attr("href"));
            System.out.println();
        }
        //这时候我们就可以按需去进行解析了..存放数据库,去重,多线程的操作就不在此赘述了.
    }

下载源码之后请先更换二维码保存路径,如果该文件夹访问权限过高,或者盘符不存在,会导致程序异常.

虽然这个爬虫并没有做后续的一些操作,但是这种爬取策略是挺有意思的.

爬虫优化

发布了47 篇原创文章 · 获赞 15 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览