左手用R右手Python系列——动态网页抓取与selenium驱
感谢关注天善智能,走好数据之路↑↑↑
欢迎关注天善智能,我们是专注于商业智能BI,人工智能AI,大数据分析与挖掘领域的垂直社区,学习,问答、求职一站式搞定!
本文作者:天善智能社区专家杜雨
天善智能社区地址:https://www.hellobi.com/
本节以下内容正式分享今日案例,目标是拉勾网(不要问为什么,因为之前我还没有爬过拉钩)!
在介绍案例之前,请确保系统具备以下条件:
本地有selenium服务器并添加系统路径;
本地有plantomjs浏览器并添加系统路径;
安装了RSelenium包。
因为涉及到自动化点击操作,Chrome浏览器倒腾一下午硬是在点击环节出故障,找到了原因,因为拉勾网页面很长,而下一页按钮不在默认视窗范围内,使用了js脚本控制滑动条失败,原因不明,看到有人用firefox浏览器测试成功,我还没有试过,这里改用plantomjs无头浏览器(无需考虑元素是否被窗口遮挡的问题。)
R语言版:
#!!!这两句是在cmd后者PowerShell中运行的!
#RSelenium服务未关闭之前,请务必保持该窗口状态!
###启动selenium服务:
cd D:\
java -jar selenium-server-standalone-3.3.1.jar
##selenium服务器也可以直接在R语言中启动(无弹出窗口)
system("java -jar \"D:/selenium-server-standalone-2.53.1.jar\"",wait = FALSE,invisible = FALSE)
#加载包
library("RSelenium")
library("magrittr")
library("xml2")
启动服务
#给plantomjs浏览器伪装UserAgent
eCap<- list(phantomjs.page.settings.userAgent="Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20120101 Firefox/29.0")
###伪装浏览器UserAgent,为什么即使使用plantomjs这种浏览器也需要伪装UA呢,
###因为plantomjs是专门用于web端页面测试的,通常都是在自己的web项目中测试web端功能,直接拿去抓别人的网站,默认的UA就是plantomjs;
###这是公然的挑衅!
###连接plantomjs服务
remDr<- remoteDriver(browserName="phantomjs", extraCapabilities= eCap)
构建自动化抓取函数:
#自动化抓取函数:
myresult<-function(remDr,url){
###初始化一个数据框,用作后期收据收集之用!
myresult<-data.frame()
###调用后台浏览器(因为是plantomjs这种无头浏览器(headless),所以你看不到弹出窗口)
remDr$open()
###打开导航页面(也就是直达要抓取的目标网址)
remDr$navigate(url)
###初始化一个计时器(用于输出并查看任务进度)
i =0
while(TRUE){
#计时器开始计数:
i = i+1
#范回当前页面DOM
pagecontent<-remDr$getPageSource()[[1]]
#以下三个字段共用一部分祖先节点,所以临时建立了一个根节点(节省冗余代码)
con_list_item <- pagecontent %>%read_html() %>% xml_find_all('//ul[@class="item_con_list"]/li')
#职位名称
position.name <- con_list_item %>% xml_attr("data-positionname")
#公司名称
position.company <- con_list_item %>% xml_attr("data-company")
#职位薪资
position.salary <- con_list_item %>% xml_attr("data-salary")
#职位详情链接
position.link <- pagecontent %>%read_html() %>% xml_find_all('//div[@class="p_top"]/a') %>% xml_attr("href")
#职位经验要求
position.exprience <- pagecontent %>%read_html() %>% xml_find_all('//div[@class="p_bot"]/div[@class="li_b_l"]') %>% xml_text(trim=TRUE)
#职位所述行业
position.industry <- pagecontent %>%read_html() %>% xml_find_all('//div[@class="industry"]') %>% xml_text(trim=TRUE) %>% gsub("[[:space:]\\u00a0]+|\\n","",.)
#职位福利
position.bonus <- pagecontent %>%read_html() %>% xml_find_all('//div[@class="list_item_bot"]/div[@class="li_b_l"]') %>% xml_text(trim=TRUE) %>% gsub("[[:space:]\\u00a0]+|\\n","/",.)
#职位工作环境
position.environment<- pagecontent %>%read_html() %>% xml_find_all('//div[@class="li_b_r"]') %>% xml_text(trim=TRUE)
#收集数据
mydata<- data.frame(position.name,position.company,position.salary,position.link,position.exprience,position.industry,position.bonus,position.environment,stringsAsFactors = FALSE)
#将本次收集的数据写入之前创建的数据框
myresult<-rbind(myresult,mydata)
#系统休眠0.5~1.5秒
Sys.sleep(runif(1,0.5,1.5))
#判断页面是否到尾部
if( pagecontent %>%read_html() %>% xml_find_all('//div[@class="page-number"]/span[1]') %>% xml_text() !="30"){
#如果页面未到尾部,则点击下一页
remDr$findElement('xpath','//div[@class="pager_container"]/a[last()]')$clickElement()
#但因当前任务进度
cat(sprintf("第【%d】页抓取成功",i),sep ="\n")
}else{
#如果页面到尾部则跳出while循环
break
}
}
#跳出循环后关闭remDr服务窗口
remDr$close()
#但因全局任务状态(也即任务结束)
cat("all work is done!!!",sep ="\n")
#返回最终数据
return(myresult)
}
运行抓取函数
url <-"https://www.lagou.com/zhaopin"
myresult <- myresult(remDr,url)
#预览
DT::datatable(myresult)
Python:
importos,random,time
importpandasaspd
fromseleniumimportwebdriver
fromselenium.webdriver.common.desired_capabilities
importDesiredCapabilities
fromlxmlimportetree
启动服务
dcap = dict(DesiredCapabilities.PHANTOMJS)
#这里也是伪装一下UA:
dcap["phantomjs.page.settings.userAgent"] = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:25.0) Gecko/20100101 Firefox/25.0")
#启动服务(python里面的selenium内置有selenium服务器,需要本地启动)
driver = webdriver.PhantomJS(desired_capabilities=dcap)
构建抓取函数
defgetlaogou(driver,url):
#初始化一个长度为0的空字典!以备之后收集数据
myresult = {
"position_name":[],
"position_company":[],
"position_salary":[],
"position_link":[],
"position_exprience":[],
"position_industry":[],
"position_environment":[]
};
#导航到目标网址
driver.get(url)
#计时器初始化
i =0
whileTrue:
#计时器累计计时:
i+=1
#获取当前页面DOM
pagecontent = driver.page_source
#解析HTML文档
result = etree.HTML(pagecontent)
#使用字典内单个list的extend方法累计收集数据
myresult["position_name"].extend(result.xpath('//ul[@class="item_con_list"]/li/@data-positionname'))
myresult["position_company"].extend(result.xpath('//ul[@class="item_con_list"]/li/@data-company'))
myresult["position_salary"].extend(result.xpath('//ul[@class="item_con_list"]/li/@data-salary'))
myresult["position_link"].extend(result.xpath('//div[@class="p_top"]/a/@href'))
myresult["position_exprience"].extend([ text.xpath('string(.)').strip()fortextinresult.xpath('//div[@class="p_bot"]/div[@class="li_b_l"]')])
myresult["position_industry"].extend([ text.strip()fortextinresult.xpath('//div[@class="industry"]/text()')])
myresult["position_environment"].extend(result.xpath('//div[@class="li_b_r"]/text()'))
#单次循环任务休眠
time.sleep(random.choice(range(3)))
#判断页面是否到尾部
ifresult.xpath('//div[@class="page-number"]/span[1]/text()')[0] !='30':
#如果未到达页面尾部,则点击下一页:
driver.find_element_by_xpath('//div[@class="pager_container"]/a[last()]').click()
#同时打印当前任务 状态!
print("第【{}】页抓取成功!".format(i))
else:
#如果所有页面到达尾部,则跳出循环!
break
#打印全局任务状态
print("everything is OK")
#退出并关闭selenium服务!
driver.quit()
#返回数据
returnpd.DataFrame(myresult)
运行抓取程序
url ="https://www.lagou.com/zhaopin"
mydata = getlaogou(driver,url)
欢迎关注天善智能www.hellobi.com,我们是专注于商业智能BI,人工智能AI,大数据分析与挖掘领域的垂直社区,学习,问答、求职一站式搞定!