vc++在webbrowser中模拟点击网页链接_RSelenium动态网页抓取

本文介绍如何使用RSelenium在VC++的webbrowser中模拟点击动态网页链接,以实现动态网页内容抓取。通过设置Selenium Server和Chrome浏览器,演示了在百度搜索并抓取搜索结果以及模拟网页滑动获取完整内容的过程。
摘要由CSDN通过智能技术生成

[编者按:周末把动态网页抓取当作一个Project来做,现攻克?️差不多了,特此记之,以飨观众]

动态网页是跟静态网页相对,特指网页的内容动态生成,比如需要在浏览器中滑动鼠标、或点击方向箭头才能看到新的东西,或者网页呈现的东西都是服务器即时生成。这些动态的内容一般通过在html文件中插入Java代码实现(至于为啥是Java,听说背后有故事,然后Java要收费了)。

今天我要涉及的动态网页主要有两个,一个是百度,另一个是非常random(河北省三甲医院大全:https://m.yyk.99.com.cn/sanjia/hebei/)。百度是常见的动态网页,因为我们输入关键词搜索后得到的结果全部依赖于Java,而第二个网页要浏览完75家医院需要鼠标滑动四次,背后同样是Java的功劳。动态网页如果用静态网页抓取的方法估计什么也抓取不到(或者抓取不全),原因是动态网页结果的显示需要借助浏览器(有时需要人和鼠标的操作)。如果想用R进行动态网页内容抓取需经过浏览器操作才能看到全部内容。所以问题的关键在于如何让R命令浏览器做事,先让浏览器把Java控制的内容部分渲染出来,然后再对结果进行内容抓取。

如何让R命令浏览器呢?目前市面上通行的方法是构造一个虚拟的服务器Selenium Server,然后让R能跟Selenium对话。Selenium是一个用于网页测试的Java开源软件,可以模拟浏览器的点击、滚动、滑动以及文字输入等操作。为了让测试环境更加纯粹、干净,我们最好在docker里进行上述测试,而docker类似一个轻量级的虚拟光驱或者镜像,可以包含测试过程中需要用到的其它软件,其中关键是Selenium测试的对象,即某个浏览器(本文采用Chrome)。

在进行动态网页抓取之前,需要做很多准备工作,大体如前一段所描述那样:

0. 确保电脑支持Java (如Mac的JDK)

1. 安装Selenium Server(模拟浏览器的点击、滚动、滑动以及文字输入等)

   下载地址:

https://docs.seleniumhq.org/download/

   下载完安装命令(terminal里运行)

java -jar selenium-server-standalone-3.141.59.jar  (注意版本号)

    Vignette可以查看: 

https://rpubs.com/johndharrison/RSelenium-Basics

2. 安装docker(虚拟光驱/镜像,构造干净的测试环境)

    下载地址:

https://docs.docker.com/docker-for-mac/install/

    相关命令说明:

https://docs.docker.com/docker-for-mac/

    Vignette可以查看:

https://cran.r-project.org/web/packages/RSelenium/vignettes/docker.html

    安装好后下载selenium浏览器(terminal里运行)

docker pull selenium/standalone-chrome

    我喜欢chrome,你可以选择其它浏览器;更多selenium浏览器可查看:https://hub.docker.com/u/selenium/

    启动selenium浏览器(terminal里运行)

docker run -d -p 4445:4444 selenium/standalone-chrome

3. Windows系统还可再安装一个软件(观察爬虫时RSelenium跟网页的互动):https://www.tightvnc.com/download.php

4. R里安装两个包:RSelenium和Rwebdriver

    安装说明:

https://github.com/ropensci/RSelenium

    Vignette可以查看: 

https://rpubs.com/johndharrison/RSelenium-Basics

接下来开始干正事了。第一步,连接到docker里的Selenium服务器:

library(RSelenium)    # 激活包remDr "localhost"                       , port = 4445L                      , browserName = "chrome")                     # 设置连接参数remDr$open()          # 开始连接

第二步,打开百度搜索首页,输入搜索关键词,点击搜索:

remDr$navigate("https://www.baidu.com")    # 打开remDr$screenshot(display = TRUE)           # 截屏看一下首页xpath '//*[@id="kw"]'                   # 根据上面定位在界面中找到文字输入框webElem "xpath", value = xpath)   # 在搜索框里输入搜索关键词‘R Cran’,然后点击回车键webElem$sendKeysToElement(list("R Cran", key = "enter"))   # # 再次截屏显示搜索结果remDr$screenshot(display = TRUE)

以下是我前后两次截屏的结果:

cccd4cc8293fa24abb21c9049be8310d.png

--------------------------------------

4cbe3f9aecc1fb205c9da1aab113af27.png

我们知道,百度默认一屏显示10个搜索结果。接下来的第三步我们把第一屏的10个结果给抠下来:

# 调用静态网页抓取常用包rvestlibrary(rvest)# 获取网页背后的html源代码webpage # 利用节点ID挑出10项搜索结果的内容标题result_html # 下面两行利用xpath挑出10项搜索结果的内容标题# xpath # result_html # 挑出html代码中10个标题内容result_name head(result_name,10)# 找出10个标题对应的超级链接result_link # 存成数据框result_df = data.frame(result_name=result_name, result_link=result_link)

10个搜索结果出来了,如果我们想模拟浏览器点击某个搜索结果呢?比如第一个结果“The Comprehensive R Archive Network”。下面来实现一下:

# 直接在搜索结果界面中定位10项搜索结果标题webElems 'css selector', # 把结果标题变成文本单独拎出来resHeaders function(x){x$getElementText()}))resHeaders# 准备点击第一个搜索结果webElem "The Comprehensive R Archive Network")]]# 模拟浏览器点击第一个结果超级链接,并在新窗口中打开webElem$clickElement()webElem$sendKeysToElement(list(key = "control", "w"))# 此时浏览器有两个窗口,下面几行进行窗口切换(窗口ID会动态变化)remDr$getWindowHandles()remDr$getCurrentWindowHandle()remDr$switchToWindow("CDwindow-2BA4D55F9BABCA20D3DFE2FECBA3D85A")remDr$getCurrentWindowHandle()# 获取新窗口的网址和标题,并截屏remDr$getCurrentUrl()remDr$getTitle()remDr$screenshot(display = TRUE)

第一个链接打开之后的截屏结果如下:

52398a1d6ff177a458dbd2ace0dabac7.png

以上就是用RSelenium对百度搜索结果进行动态网页抓取。接下来,我想展示一下如何模拟在浏览器页面中滑动鼠标获得多屏显示的全部内容,毕竟只有滑完之后才能看到所有网页内容,进而进行内容抓取。这里,我们借助河北省三甲医院的例子。

第一步,打开链接:

remDr$navigate("https://m.yyk.99.com.cn/sanjia/hebei/")remDr$screenshot(display = TRUE)

555de1df48e6b959a4ae6eb4c30a3712.png

不出意外的话,我们这一次能抓取20家医院的信息。

# 获取网页背后的html源代码webpage $getPageSource()[[# 找出医院名字对应的节点名称hospital_name_html 'h2')# 将医院名字从html转换为文本hospital_name # 调用stringr包把医院名字前的空格等多余符号去掉library(stringr)hospital_name "\r\n",# 看看前10家医院的名字head(hospital_name,10)# 看看总共有多少家医院length(hospital_name)    # 结果为20

事实上,经多次滑动鼠标我们发现这个页面一共包含有75家医院的信息。我们第一次抓取只能获取其中前20家是因为后面医院信息需要先滑动鼠标。

接下来,我们借助在R中运行Java代码来达到在当前网页中滑动鼠标的效果。而且,我们不想一次一次的滑动,而是一下要滑倒页面的最底部。

# window.scrollTo是Java的函数,括号里跟着x和y的屏幕位置数字。比如第一个0表示屏幕最左端;# document.body.scrollHeight表示屏幕上鼠标一次滑动的最大高度,即当面页面的最底部。# 那么,下面的代码显示我们要重复地滑到页面的最底端,每次滑动中间停顿3秒,好让网页内容得以显示。# 最后,滑到不能再滑动的时候,我们就停住了。比如,第一个0表示屏幕最左端,last_height = 0 #repeat {  remDr$executeScript("window.scrollTo(0,document.body.scrollHeight);")  Sys.sleep(3) #delay by 3sec to give chance to load.     # Updated if statement which breaks if we can't scroll further   new_height = remDr$executeScript("return document.body.scrollHeight")  if(unlist(last_height) == unlist(new_height)) {    break  } else {    last_height = new_height  }}

这样把这个网页的所有内容显示全之后,我们再按照静态网页抓取就可以把75家医院的所有数据抓取下来:

webpage $getPageSource()[[hospital_name_html 'h2')hospital_name library(stringr)hospital_name "\r\n",head(hospital_name,10)length(hospital_name)    # 结果为75

至此,我们解决了动态网页抓取的两个主要问题:一是抓取搜索引擎生成的搜索结果界面的相关内容;二是抓取多屏显示的动态网页相关内容。当然,这两个问题难以涵盖动态网页抓取的其它诸多情况。比如后者还包括点击动态网页中的方向箭头(以显示其它隐藏内容),抓取同一网页中不同栏(frame界面)的不同内容,等等等等。

在我摸索过程中,我还发现我虽然能抓取百度搜索结果,但是google的结果却难以实现。一位知情人士告诉我说,虽然你电脑里的浏览器能用VPN打开google,但是Selenium并没有VPN可以打开google,此言不假。因此,我通过google搜索找到了很多如何用RSelenium抓取google搜索结果的方法,本想复制一下,却发现同样的方法在我这却行不通。

罢了罢了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值