赞
踩
在爬虫领域,selenium几乎是最无所不能的一个框架了,在传统的爬虫无能为力的时候,我们可以使用selenium来请求动态页面获取信息。
当然,只有selenium还是不够的,因为使用selenium我们只能获取页面上展示的数据,但是无法获取Network请求和响应结果,有些网页并不会将从接口接收到的所有数据都展示到页面上,为了捕捉到这些信息,我们就需要引入到browsermob。这两个框架的强强联合,几乎可以解决我们99%的需求。
一般情况下使用selenium都是重新开一个浏览器,但是这样会产生一些问题,比如有一些网站你需要登录后才能查询到信息,如果每次都重新开一个浏览器的话,我们就需要重复进行登录的操作,这样非常繁琐。为了适应这样的场景,我们可以打开一个浏览器,然后让selenium将浏览器接管,这样浏览器就会保留我们的登录信息,selenium可以很方便地开始工作。
为了能让selenium顺利接管浏览器,我们首先需要指定端口号来打开浏览器。
首先找到 chrome.exe 快捷方式指向的具体地址,然后将这个地址加入到环境变量
添加完环境变量后,我们就可以使用某个指定的端口打开一个chrome客户端
接着我们在selenium中使用配置信息启动Chrome就可以接管客户端了
在selenium接管浏览器后,我们就可以进行响应操作。我们这边简单地爬取一下百度首页的热搜信息来熟悉一下操作。
首先介绍一下本文会用到的jar包。
- <dependency>
- <!-- fastjson -->
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>1.2.47</version>
- </dependency>
-
-
- <dependency>
- <groupId>cn.hutool</groupId>
- <artifactId>hutool-core</artifactId>
- <version>5.6.5</version>
- </dependency>
-
-
- <dependency>
- <groupId>net.lightbody.bmp</groupId>
- <artifactId>browsermob-core</artifactId>
- <version>2.1.5</version>
- </dependency>
-
- <dependency>
- <groupId>net.lightbody.bmp</groupId>
- <artifactId>browsermob-legacy</artifactId>
- <version>2.1.5</version>
- </dependency>
-
- <dependency>
- <groupId>org.seleniumhq.selenium</groupId>
- <artifactId>selenium-java</artifactId>
- <version>4.1.1</version>
- </dependency>
-
-
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- <version>31.0.1-jre</version>
- </dependency>
百度热搜是放在一个<ul>标签下的,并且id为hotsearch-content-wrapper,使用这个id可以找到这个元素,然后逐个遍历其中的<li>就能得到首页的6个热搜信息。
不难发现,每个<li>标签里面都有一个<a>标签用来表示url地址,还有一个<span>标签用来表示热搜的标题,我们主要关注这个两个元素对应的信息
这里简单贴一下selenium中findElement的api
基本上以上的几个方法就可以解决我们的需求了。
代码非常简单
- @Override
- public void startSelenium() {
- log.debug("开启浏览器");
- System.setProperty("webdriver.chrome.driver", DRIVER_PATH);
- ChromeOptions options = new ChromeOptions();
- options.setExperimentalOption("debuggerAddress", "127.0.0.1:9222");
- WebDriver driver = new ChromeDriver(options);
- log.debug("浏览器启动成功");
- driver.get("http://www.baidu.com");
- log.debug("开始获取热搜信息");
- WebElement element = driver.findElement(By.id("hotsearch-content-wrapper"));
- List<WebElement> element_lis = element.findElements(By.tagName("li"));
- for(WebElement el : element_lis) {
- String url = el.findElement(By.tagName("a")).getAttribute("href");
- String title = el.findElement(By.className("title-content-title")).getText();
- log.info(title + "=>" + url);
- }
-
- }
运行一下代码得到如下信息就代表大功告成啦
大部分网站使用selenium都可以获取数据,但是有一些网站并不会将所有获取的数据都进行展示,或者说,我们直接读取接口返回的数据会更快速的获取数据,我们这里以淘宝联盟举例。
淘宝联盟的url如下,需要进行登录
阿里妈妈https://pub.alimama.com/portal/v2/pages/promo/goods/index.htm进入到页面后,我们可以发现获取数据的接口是 union.pub.entry,我们可以直接从这个接口获取数据,这样就不需要到页面中去找了。
在编码的时候发现了一个问题,就是使用selenium+browsermob的时候没办法对已经打开的浏览器配置代理信息,所以如果使用selenium接管已经打开的浏览器是拿不到Network数据的,所以本文只能退而求其次,让selenium打开新的浏览器,然后进行登录。
browsermob-proxy +selenium使用 - 知乎browsermob-proxy 一个浏览器的代理 在调试浏览器或者爬取数据的时候,需要使用浏览器的开发者模式,尤其是动态网页,在使用selenium的时候,想要知道到底调用了哪些接口 ##安装 pip install browsermob-proxy这里…https://zhuanlan.zhihu.com/p/363008064我们首先需要实例化browsermob的代理,然后将代理添加到selenium的参数中,接着再实例化selenium,打开chrome浏览器。使用browsermob获取网络请求的方法就是设置两个回调函数,一个是请求的回调函数,一个是响应的回调函数。回调函数的意思就是,有请求或者响应信息的时候,就会执行我们回调函数里面编写的代码。
- public void startSelenium() {
-
- // 实例化BrowserMob代理
- System.setProperty("webdriver.chrome.driver", DRIVER_PATH);
- BrowserMobProxy browserMobProxy = new BrowserMobProxyServer();
- browserMobProxy.start();
- browserMobProxy.enableHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT);
- browserMobProxy.setHarCaptureTypes(CaptureType.RESPONSE_CONTENT);
- browserMobProxy.newHar("kk");
- Proxy seleniumProxy = ClientUtil.createSeleniumProxy(browserMobProxy);
-
- // 实例化Selenium
- ChromeOptions options = new ChromeOptions();
- options.setProxy(seleniumProxy);
- options.setAcceptInsecureCerts(true);
- //options.setExperimentalOption("debuggerAddress", "127.0.0.1:9222");
- WebDriver driver = new ChromeDriver(options);
-
-
- // 网络请求回调函数
- browserMobProxy.addRequestFilter(new RequestFilter() {
- @Override
- public HttpResponse filterRequest(HttpRequest httpRequest, HttpMessageContents httpMessageContents, HttpMessageInfo httpMessageInfo) {
- // 打印请求信息
- // log.info("request=>" + httpMessageInfo.getUrl());
- return null;
- }
- });
-
- // 网络响应回调函数
- browserMobProxy.addResponseFilter(new ResponseFilter() {
- @Override
- public void filterResponse(HttpResponse httpResponse, HttpMessageContents httpMessageContents, HttpMessageInfo httpMessageInfo) {
- // 这里获取打印的信息
- log.info(httpMessageInfo.getUrl());
- if(httpMessageInfo.getUrl().equals("https://pub.alimama.com/openapi/param2/1/gateway.unionpub/union.pub.entry")) {
- // 格式化输出
- String str = JSONObject.toJSONString(httpMessageContents.getTextContents(), true);
- System.out.println(str);
- // 将数据写到文件中
- try {
- FileWriter writer = new FileWriter("output.txt");
- writer.write(str);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- });
-
- // 打开网页
- driver.get("https://pub.alimama.com/portal/v2/pages/promo/goods/index.htm?pageNum=2");
-
-
- }
执行上述代码,打开浏览器并且登录后,我们就可以拿到相应接口的响应信息了,在项目的根目录看到output.txt就代表数据获取成功,可以发现这个接口的响应数据非常大,里面包含的信息非常多。
到这里,本文的主要内容就介绍完了。使用selenium+browsermob可以非常方便地进行网络数据收集,不过我感觉有一个缺点就是运行起来非常慢,在爬下批量数据的情况下可以使用,但是如果要快速爬取大批量数据的话,还是直接用http去请求接口,对于反爬虫机制比较好的接口,可以去研究一下js逆向,selenium相对于直接去请求接口的一大优势就是不用花时间去研究js逆向,直接写代码去获取数据就完事了。
那么本文就到此结束,如果你有什么想和我交流讨论欢迎评论区留言。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。