zoukankan      html  css  js  c++  java
  • Java爬虫系列四:使用selenium-java爬取js异步请求的数据

    在之前的系列文章中介绍了如何使用httpclient抓取页面html以及如何用jsoup分析html源文件内容得到我们想要的数据,但是有时候通过这两种方式不能正常抓取到我们想要的数据,比如看如下例子。

    1.需求场景:

    想要抓取股票的最新价格,页面F12信息如下:

    按照前面的方式,爬取的代码如下:

    /**
     * @description: 爬取股票的最新股价
     * @author: JAVA开发老菜鸟
     * @date: 2021-10-16 21:47
     */
    public class StockPriceSpider {
    
        Logger logger = LoggerFactory.getLogger(this.getClass());
    
        public static void main(String[] args) {
    
            StockPriceSpider stockPriceSpider = new StockPriceSpider();
            String html = stockPriceSpider.httpClientProcess();
            stockPriceSpider.jsoupProcess(html);
        }
    
        private String httpClientProcess() {
            String html = "";
            String uri = "http://quote.eastmoney.com/sh600036.html";
            //1.生成httpclient,相当于该打开一个浏览器
            CloseableHttpClient httpClient = HttpClients.createDefault();
            CloseableHttpResponse response = null;
            //2.创建get请求,相当于在浏览器地址栏输入 网址
            HttpGet request = new HttpGet(uri);
            try {
                request.setHeader("user-agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36");
                request.setHeader("accept", "application/json, text/javascript, */*; q=0.01");
    
    //            HttpHost proxy = new HttpHost("3.211.17.212", 80);
    //            RequestConfig config = RequestConfig.custom().setProxy(proxy).build();
    //            request.setConfig(config);
    
                //3.执行get请求,相当于在输入地址栏后敲回车键
                response = httpClient.execute(request);
    
                //4.判断响应状态为200,进行处理
                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    //5.获取响应内容
                    HttpEntity httpEntity = response.getEntity();
                    html = EntityUtils.toString(httpEntity, "utf-8");
                    logger.info("访问{} 成功,返回页面数据{}", uri, html);
                } else {
                    //如果返回状态不是200,比如404(页面不存在)等,根据情况做处理,这里略
                    logger.info("访问{},返回状态不是200", uri);
                    logger.info(EntityUtils.toString(response.getEntity(), "utf-8"));
                }
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //6.关闭
                HttpClientUtils.closeQuietly(response);
                HttpClientUtils.closeQuietly(httpClient);
            }
            return html;
        }
    
        private void jsoupProcess(String html) {
            Document document = Jsoup.parse(html);
            Element price = document.getElementById("price9");
            logger.info("股价为:>>> {}", price.text());
        }
    
    }
    

    运行结果:

    纳尼,股价为"-" ?不可能。
    之所以爬不到正确的结果,是因为这个值在网站上是通过异步加载渲染的,因此不能正常获取。

    2.java爬取异步加载的数据的方法

    那如何爬取异步加载的数据呢?通常有两种做法:

    2.1内置浏览器内核

    内置浏览器就是在抓取的程序中启动一个浏览器内核,使我们获取到 js 渲染后的页面就和静态页面一样。常用的内核有

    • Selenium
    • PhantomJs
    • HtmlUnit

    这里我选了Selenium,它是一个模拟浏览器,是进行自动化测试的工具,它提供一组 API 可以与真实的浏览器内核交互。当然,爬虫也可以用它。
    具体做法如下:

    • 引入pom依赖
    <dependency>
       <groupId>org.seleniumhq.selenium</groupId>
       <artifactId>selenium-java</artifactId>
       <version>3.141.59</version>
    </dependency>
    
    • 配置对应浏览器的驱动
      要使用selenium,需要下载浏览器的驱动,根据不同的浏览器要下载的驱动程序也不一样,下载地址为:https://npm.taobao.org/mirrors/chromedriver/
      我用的是谷歌浏览器,因此下载了对应版本的windows和linux驱动。

      下载后需要配置进java环境变量里面,指定驱动的目录:

      System.getProperties().setProperty("webdriver.chrome.driver", "F:/download/chromedriver_win32_1/chromedriver.exe");

    • 代码实现:

      Logger logger = LoggerFactory.getLogger(this.getClass());
      
        public static void main(String[] args) {
      
            StockPriceSpider stockPriceSpider = new StockPriceSpider();
            stockPriceSpider.seleniumProcess();
        }
      
        private void seleniumProcess() {
      
            String uri = "http://quote.eastmoney.com/sh600036.html";
      
            // 设置 chromedirver 的存放位置
            System.getProperties().setProperty("webdriver.chrome.driver", "F:/download/chromedriver_win32_1/chromedriver.exe");
      
            // 设置浏览器参数
            ChromeOptions chromeOptions = new ChromeOptions();
            chromeOptions.addArguments("--no-sandbox");//禁用沙箱
            chromeOptions.addArguments("--disable-dev-shm-usage");//禁用开发者shm
            chromeOptions.addArguments("--headless"); //无头浏览器,这样不会打开浏览器窗口
            WebDriver webDriver = new ChromeDriver(chromeOptions);
      
            webDriver.get(uri);
            WebElement webElements = webDriver.findElement(By.id("price9"));
            String stockPrice = webElements.getText();
            logger.info("最新股价为 >>> {}", stockPrice);
            webDriver.close();
        }
      

      执行结果:

      爬取成功!

    2.2反向解析法

    反向解析法就是通过F12查找到 Ajax 异步获取数据的链接,直接调用该链接得到json结果,然后直接解析json结果获取想要的数据。
    这个方法的关键就在于找到这个Ajax链接。这种方式我没有去研究,感兴趣的可以百度下。这里略。

    3.结束语

    以上即为如何通过selenium-java爬取异步加载的数据的方法。通过本方法,我写了一个小工具:
    持仓市值通知系统,他会每日根据自己的持仓配置,自动计算账户总市值,并邮件通知到指定邮箱。
    用到的技术如下:

    相关代码已经上传到我的码云,感兴趣可以看下。

    本文来自博客园,作者:JAVA开发老菜鸟,转载请注明原文链接:https://www.cnblogs.com/sam-uncle/p/15415526.html

  • 相关阅读:
    Solidity通过合约转ERC20代币
    各种开源协议区别
    shell脚本之函数
    shell脚本之循环和循环控制
    shell脚本之if判断以及case多分支选择
    shell脚本之数组
    shell脚本之变量
    nginx常用内置变量
    nignx配置文件详解
    nginx源码安装./configure常见参数详解
  • 原文地址:https://www.cnblogs.com/sam-uncle/p/15415526.html
Copyright © 2011-2022 走看看