使用Selenium模拟浏览器,实现自动爬取数据

最近需要在一个网站下载一批数据。但是输入一个查询,返回三四万条结果,每次只能导出500条,而且每次还得输入下载条目的范围!这样点击下载,还不要了我的老命。于是乎想自动化这个过程。

我的需求主要是两点:1. 要求自动化程度高。最好有直接模拟浏览器鼠标和键盘动作的成熟接口,比如在文本框输入,选择下拉列表,单选框,复选框,点击按钮等。2. 不要求效率。因为我要的数据量相对来说很小。3. python下的框架。因为平时几乎主要用python。

我不太懂网站技术,和网站沾边的经验只有两个:开发过一个很简单安卓的客户端,用python的scrapy框架写过爬虫来自动爬取新闻。所以了解一些客户端和服务端基本的交互方式、了解如何分析网页源代码、了解xpath语法。

刚开始针对这个问题,我连搜啥都不太清楚。知乎的这篇文章提供了很多有用信息:“Python 爬虫如何获取 JS 生成的 URL 和网页内容?” 顺着它我又权衡了很多方法,最后选择了Selenium。主要优点是学习成本极小,代码实现快。缺点是爬取效率低。想要高效率的朋友,就要花一些时间学习更复杂的工具包了。

网站技术

想要自动爬取网页,得了解一些基本的知识,这样做起来更快。这里简单介绍一下相关知识。

1. Request/response

request是客户端向服务端发起请求。输入一个网址对应一个request动作,这是最直观的。爬取静态网页的内容,只要知道网址就可以了。但是现在的网页很多都是动态的,鼠标指向或者点击网页中某些元素也会触发request动作,从而使网页动态更新部分内容,这部分内容是不能直接从静态网页中获取的。这种技术叫AJAX,不过我不太懂。这里的问题是我们可能根本不知道网址是什么,因此需要一些高级的接口,能处理动态内容。

response是服务端给客户端的返回内容。想要获取静态网页内容的话,直接从requeson里取就好了。

2. 分析网页源码

我们想要爬取网页上的某一部分信息,需要知道如何能定位到它。这里需要HTML,XPATH的知识。不知道的可以上w3school 在线教程:http://www.w3school.com.cn

查看网页源代码,鼠标指针指向网页任意地方,或者指向目标元素。右键鼠标,在下拉列表选择“检查元素”即可。如下是我右键“百度一下”所显示的网页源代码,是HTML格式的,我们可以看到对应的HTML代码。把它提取出来,我们可能需要div//@[class="head_wrapper"]//input[@type="submit"]的语句,这是XPATH语法,很好掌握。知道如何分析网页,我们又进了一步。

3. 网页基本元素操作

前进、后退、刷新、打开新选项卡、输入网址等;

文本框输入、选择下拉列表、单选框、复选框、点击按钮等。

我这里需要模拟的操作也就这么多了,对应的selenium接口可以参考 http://www.cnblogs.com/Ming8006/p/5727542.html。

4. Selenium介绍

一句话:Selenium是一个web应用的自动化测试工具集

好多句话:Selenium 诞生于 2004 年,当在 ThoughtWorks 工作的 Jason Huggins 在测试一个内部应用时。作为一个聪明的家伙,他意识到相对于每次改动都需要手工进行测试,他的时间应该用得更有价值。他开发了一个可以驱动页面进行交互的 Javascript 库,能让多浏览器自动返回测试结果。那个库最终变成了 Selenium 的核心,它是 Selenium RC(远程控制)和 Selenium IDE 所有功能的基础。

实战练习

1.分析数据获取的过程

我的数据获取过程如下:

在A页面输入查询语句,点击submit;浏览器自动新开一个页面,跳转到新页面B,在文本框输入下载条目的范围;点击Export弹出弹窗,然后在下拉列表、单选框、复选框做一些选择,点击下载。然后浏览器就开始下载文件了。

网页A

网页B

2. 爬取过程

 A. 安装Selenium

Selenium支持多种浏览器,我选用google chrome。下载地址:https://sites.google.com/a/chromium.org/chromedriver/。同时,当然要在python中安装selenium。 命令行输入pip install senenium 即可安装。

 B. 配置环境变量

这一步需要将chromedriver的保存路径配置到操作系统的环境变量中,好让selenium能找到chromedriver。windows下配置环境变量PATH,linux或者mac可以选择配置到 .bash_rc中。配置方法很多,自行百度。

我用的是mac,不知为什么配置了不起作用!后来发现只有在代码里设置才能起作用。

C. 核心代码(python)

# 设置下载路径,将路径配置到ChromeOptions。

chromeptions = webdriver.ChromeOptions()

prefs = {'profile.default_content_settings.popups':0,'download.default_directory': query_dir}

chromeptions.add_experimental_option('prefs', prefs)

# 设置环境变量,启动浏览器。

chromedriver = CHROMEDRIVER_DIR    # 设置成你自己的路径

os.environ["webdriver.chrome.driver"] = chromedriver

driver = webdriver.Chrome(executable_path=chromedriver,chrome_options=chromeptions)

# 设置隐形等待时间,因为点击后网站一段时间后才能返回内容,如果不等待会报超时异常。

driver.implicitly_wait(IMPLICIT_WAIT_TIME)

# 请求网页A

driver.get("http://demo.ovid.com/demo/ovidsptools/launcher.htm")

# 在网页A的两个文本框输入,并提交。

driver.find_element_by_name('D').clear()

driver.find_element_by_name('D').send_keys('mesz')

driver.find_element_by_name('SEARCH').clear()

driver.find_element_by_name('SEARCH').send_keys(str_search_query)

driver.find_element_by_name('ovid').click()

#  跳转到新窗口,并将焦点定位到该窗口。

current_window_handle = driver.current_window_handle

for hdl in driver.window_handles:   # selenium总是有两个handle

    if hdl != current_window_handle:

        new_window_handle = hdl

driver.switch_to.window(new_window_handle)

driver.implicitly_wait(IMPLICIT_WAIT_TIME)

# 获取到网页。首先获取返回的总条目数,然后提取文本框输入下载条目的范围,如1-500。然后点击Export。

# 注意:等待页面加载完成后再计算下载次数

search_ret_num = WebDriverWait(driver, EXPLICIT_WAIT_TIME,  EXPLICIT_WAIT_INTERVAL).until(EC.presence_of_element_located((By.XPATH,'//*[@id="searchaid-numbers"]')))

search_ret_num =int(re.findall(r'\d+', search_ret_num.text.encode('utf-8'))[0])

 list_range = chunks_by_element(range(1, search_ret_num+1), DOWNLOAD_NUM_PER_TIME)

for item in list_range:

    download_range = driver.find_element_by_xpath('//*[@id="titles-display"]//input[@title="Range"]')

    download_range.clear()

    download_range.send_keys('{}-{}'.format(item[0], item[-1]))

# 点击 Export

export = driver.find_element_by_xpath('//*[@id="titles-display"]//input[@value="Export"]')

export.click()

# 获取到弹窗。进行一些设置。

driver.switch_to.alert

WebDriverWait(driver, EXPLICIT_WAIT_TIME, EXPLICIT_WAIT_INTERVAL).until(EC.presence_of_element_located((By.XPATH,'//div[@id="export-citation-popup"]')))

# 设置下载文件的一些配置

export_to_options = driver.find_element_by_xpath('//select[@id="export-citation-export-to-options"]')

export_to_options.find_element_by_xpath('//option[@value="xml"]').click()# XML

# 设置 citation content radio

citation_options = driver.find_element_by_xpath('//ul[@id="export-citation-options"]')

citation_options.find_element_by_xpath('//input[@value="ALL"]').click()#  Complete Reference

# 设置 include check-box

citation_include = driver.find_element_by_xpath('//div[@id="export-citation-include"]')

ifcitation_include.find_element_by_xpath('//input[@name="externalResolverLink"]').is_selected():# Link to External Resolver

citation_include.find_element_by_xpath('//input[@name="externalResolverLink"]').click()

ifcitation_include.find_element_by_xpath('//input[@name="jumpstartLink"]').is_selected():# Include URL

citation_include.find_element_by_xpath('//input[@name="jumpstartLink"]').click()

ifcitation_include.find_element_by_xpath('//input[@name="saveStrategy"]').is_selected():# Search History

citation_include.find_element_by_xpath('//input[@name="saveStrategy"]').click()

# 点击下载。

download = driver.find_element_by_xpath('//div[@class ="export-citation-buttons"]')

download.click()

finally:

sleep(30)# wait for finishing downloading the last file

# driver.implicitly_wait(30) # doesn't work!

driver.quit()

return

3. 小贴士

A. 每次启动一个浏览器,桌面就会真的弹出一个浏览器。你可以清晰地看到自动化过程是如何的。看来selenium真的就是为web程序的自动化测试准备的。另外,爬取过程中要注意屏幕保持打开。如果进入休眠或者屏保,也会抛出异常的。

B. 模拟网页操作的时候,网页跳转是很常见的场景。因此要注意网页响应时间。selenium不会等待网页响应完成再继续执行代码,它会直接执行。二者应该是不同的进程。这里可以选择设置隐性等待和显性等待。在其他操作中,隐性等待起决定性作用,在WebDriverWait..中显性等待起主要作用,但要注意的是,最长的等待时间取决于两者之间的大者,如果隐性等待时间 > 显性等待时间,则该句代码的最长等待时间等于隐性等待时间。

C. 设置下载路径时,刚开始怎么都不起作用。我怀疑是key “download.default_directory”不对,于是通过查看网页源代码,找到了key,依然一样的。问题出在其他地方。不过这里提醒了我,以后在代码中用字典做相关的配置时,可以通过查看源代码的方式来猜测。

D. 原以为实现整个过程最起码的两三天,因为我真的不懂。从开始学习到做完不到一个白天就完成了。估计是因为我动手之前搜了很长时间,反复比对之后,找了个最得心应手的工具。

E. 完成后我在github上搜了一圈,发现了一个神器https://github.com/voliveirajr/seleniumcrawler。 对于想爬取大量内容的朋友,如果还不想浪费时间学习太多web应用底层的知识,可以结合使用Selenium+scrapy。scrapy可以负责搜索网页,selenium负责处理每个网页上的内容,尤其是动态内容。下次我如果有需求,打算用这个思路了!

F. 分享一句话。“关于爬虫,涨经验最快的方式是:学学怎么写网站,你知道网站是什么发请求的,就知道怎么爬网站了!” 很简单吧,不过这么简单的一句话给我很大的启发。之前就是感觉太难,一直停留在scrapy爬取静态网页的水平。而且像cookies之类的技术也看了,看一次忘一次。现在看来,还是因为没有把网站的整体流程梳理清楚。另一方面,也是畏惧那些繁杂的网站技术名词。其实只要上网查查相关的概念怎么回事,慢慢就打通了。

G. 最后,完全不懂编程的人可以用一些可视化的爬虫工具,这里有一些介绍:https://www.sdk.cn/news/4801。懂编程的且想要高效率的就需要参考其他工具了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容