R语言基于selenium模拟浏览器抓取ASCO数据-连载NO.03
A:当前获取数据的网站是ASCO,xpath代码是对应网站内的搜索框、搜索按钮、翻页等功能,都经过反复验证,可以正确获取需要的数据
B:当前数据获取没有经过海量数据验证,目前经过实际获取的3个关键词数据量在1w左右,所以如果需要百万级等以上的数据还需要更多的避免抓取异常和抓取性能的优化
C:selenium版本不宜过高,会导致java调用不兼容,无法正常启动java服务或者正常拉起浏览器(大概是这个意思),已经尝试过更高版本的selenium
1、目标网站和内容准备
#添加需要搜索的内容
search_content <- c("content1","content2","content3")
#需要获取数据的网址
spider_url_base <- "https://meetings.asco.org/abstracts-presentations/search?query=*&q=*&sortBy=Relevancy&pageNumber=1&filters=%7B%22meetingTypeName%22:%5B%7B%22key%22:%22ASCO%20Annual%20Meeting%22%7D%5D,%22meetingYear%22:%5B%7B%22key%22:%222025%22%7D%5D%7D&size=20"
2、隐藏selenium特征(简单设置,表头、IP池策略等等都没有做,用处不大,未经过大量验证)
# 隐藏Selenium特征的JavaScript代码
hide_automation_script <- "
Object.defineProperty(navigator, 'webdriver', {get: () => undefined
});
window.chrome = {runtime: {},// etc.
};
const originalQuery = window.navigator.permissions.query;
window.navigator.permissions.query = (parameters) => (parameters.name === 'notifications' ?Promise.resolve({ state: Notification.permission }) :originalQuery(parameters)
);
"
3、启动java服务和浏览器
#每次获取xpath位置后点击、发送内容等操作最好间隔点时间,否则极大可能造成操作无效
#启动selenium服务
system("java -jar \"你的selenium文件路径/selenium-server-standalone-3.141.59.jar \" -port 4445",wait = FALSE,invisible = FALSE)remdr <- remoteDriver(browserName ="firefox",version='0.36.0',port=4445)
#如果port被占用,cmd中查看端口占用netstat -ano
#打开浏览器
remdr$open()
4、跳转至目标网站并处理网站弹窗
Sys.sleep(runif(1, 2, 5))#暂停下再导航到对应网页
# 导航到目标网页
#跳转到目标网站,注意网站打开的时间消耗
remdr$navigate(spider_url_base )
#这里是为了确认网站的cookies弹窗
url_cookies_accept <- remdr$findElement("xpath", "//button[@id='onetrust-accept-btn-handler'][text()='Accept All']")
Sys.sleep(runif(1, 2, 5))#暂停下再导航到对应网页
url_cookies_accept$clickElement()# 在每次请求前执行JavaScript
remdr$executeScript(script = hide_automation_script)
5、数据抓取与保存
#准备好存储数据的表
asco_data_cancer_all <- data.frame()
asco_data_cancer_each<- data.frame()
asco_data_cancer_pageeach<- data.frame()#搜索了3个关键词,所以最外层循环是3次
for (i in 1:3) {# 定位搜索框并输入内容search_box <- remdr$findElement(using = "xpath", value = "//*[@id='smallSearchbar']") # 替换为实际的搜索框XPathsearch_box$sendKeysToElement(list(search_content[i])) # 替换为实际的搜索查询Sys.sleep(runif(1, 3, 6))#暂停下再点击# 定位搜索按钮并点击search_button <- remdr$findElement(using = "xpath", value = "//mat-icon[@class='mat-icon notranslate material-icons mat-icon-no-color ng-star-inserted' and @aria-hidden='true']") # 替换为实际的搜索按钮XPathSys.sleep(runif(1, 5, 10))#暂停下再点击search_button$clickElement()# 获取完整HTML内容,这里是为了获取页数page_html_source <- remdr$getPageSource()[[1]]cat(sprintf("Progress: %s",str_c( search_content[i],"的文章信息已开始提取,当前时间:",Sys.time())),sep='\n')Sys.sleep(runif(1, 5, 9))asco_data_cancer_each <- data.frame()loop_times=0#初始循环次数,为了知道数据获取的情况repeat{# 获取完整HTML内容page_html_source <- remdr$getPageSource()[[1]]page_html_content <- rvest::read_html(page_html_source)#获取文章名称article_name=page_html_content %>%html_nodes(xpath = "//input[contains(@class,'mat-checkbox-input') and contains(@class,'cdk-visually-hidden')]/@aria-label") %>%html_text()#获取文章类型article_type=page_html_content %>%#这个xpath值定位也可以://div/span[@class="ng-star-inserted" and not(span/@class)]html_nodes(xpath = "//div[@class='eyebrow'][text()='Abstracts & Presentations']/following-sibling::div//span") %>% html_text()#获取文章链接article_link=page_html_content %>%html_nodes(xpath = "//asco-link[@class='pseudo-hover']//a[@href]") %>% html_attr('href')#每一页数据合并
asco_data_cancer_pageeach=data.frame(article_name[-1],article_type,article_link,cancer_type=search_content[i])#当前关键词所有页数据合并asco_data_cancer_each=bind_rows(asco_data_cancer_each,asco_data_cancer_pageeach)#数据获取进度proc.time() - ptmcurrent_page_url=remdr$getCurrentUrl()[[1]]#获取当前页面的网址Sys.sleep(runif(1, 10, 15))#下一页点击nextpage_button <- remdr$findElement(using = "xpath", value = "//mat-icon[contains(., 'arrow_right')]") # Sys.sleep(runif(1, 6, 10))nextpage_button$clickElement()#如果间隔很短点击可能翻页不能及时生效Sys.sleep(runif(1, 1, 3))nextpage_button$clickElement()#如果间隔很短点击可能翻页不能及时生效Sys.sleep(runif(1, 5, 10))next_page_url=remdr$getCurrentUrl()[[1]]#获取下一页面的网址loop_times=loop_times+1cat("翻页前后2个页面是否相同",current_page_url,"第",loop_times,"个",current_page_url==next_page_url,sep="\n")if(current_page_url==next_page_url){cat("已到达最后一页,URL未变化","当前页:",current_page_url,"下一页:",next_page_url,sep='\n')break}}#所有关键词数据合并asco_data_cancer_all=bind_rows(asco_data_cancer_all,asco_data_cancer_each)Sys.sleep(runif(1, 5, 10))#清空搜索框内容search_box <- remdr$findElement(using = "xpath", value = "//*[@id='smallSearchbar']") # 替换为实际的搜索框XPathSys.sleep(runif(1, 3, 6))search_box$clearElement()#清除搜索框内容}
