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

  • 相关阅读:
    ubuntu下安装maven
    159.Longest Substring with At Most Two Distinct Characters
    156.Binary Tree Upside Down
    155.Min Stack
    154.Find Minimum in Rotated Sorted Array II
    153.Find Minimum in Rotated Sorted Array
    152.Maximum Product Subarray
    151.Reverse Words in a String
    150.Evaluate Reverse Polish Notation
    149.Max Points on a Line
  • 原文地址:https://www.cnblogs.com/sam-uncle/p/15415526.html
Copyright © 2011-2022 走看看