使用Selenium模擬瀏覽器淘钟,實現(xiàn)自動爬取數(shù)據(jù)

最近需要在一個網(wǎng)站下載一批數(shù)據(jù)宦赠。但是輸入一個查詢,返回三四萬條結(jié)果米母,每次只能導(dǎo)出500條勾扭,而且每次還得輸入下載條目的范圍!這樣點擊下載铁瞒,還不要了我的老命妙色。于是乎想自動化這個過程。

我的需求主要是兩點:1. 要求自動化程度高慧耍。最好有直接模擬瀏覽器鼠標(biāo)和鍵盤動作的成熟接口身辨,比如在文本框輸入,選擇下拉列表芍碧,單選框煌珊,復(fù)選框,點擊按鈕等泌豆。2. 不要求效率定庵。因為我要的數(shù)據(jù)量相對來說很小。3. python下的框架踪危。因為平時幾乎主要用python蔬浙。

我不太懂網(wǎng)站技術(shù),和網(wǎng)站沾邊的經(jīng)驗只有兩個:開發(fā)過一個很簡單安卓的客戶端陨倡,用python的scrapy框架寫過爬蟲來自動爬取新聞敛滋。所以了解一些客戶端和服務(wù)端基本的交互方式、了解如何分析網(wǎng)頁源代碼兴革、了解xpath語法绎晃。

剛開始針對這個問題,我連搜啥都不太清楚杂曲。知乎的這篇文章提供了很多有用信息:“Python 爬蟲如何獲取 JS 生成的 URL 和網(wǎng)頁內(nèi)容庶艾?” 順著它我又權(quán)衡了很多方法,最后選擇了Selenium擎勘。主要優(yōu)點是學(xué)習(xí)成本極小咱揍,代碼實現(xiàn)快。缺點是爬取效率低棚饵。想要高效率的朋友煤裙,就要花一些時間學(xué)習(xí)更復(fù)雜的工具包了掩完。

網(wǎng)站技術(shù)

想要自動爬取網(wǎng)頁,得了解一些基本的知識硼砰,這樣做起來更快且蓬。這里簡單介紹一下相關(guān)知識楞抡。

1. Request/response

request是客戶端向服務(wù)端發(fā)起請求扇商。輸入一個網(wǎng)址對應(yīng)一個request動作健盒,這是最直觀的寸士。爬取靜態(tài)網(wǎng)頁的內(nèi)容遮精,只要知道網(wǎng)址就可以了巧涧。但是現(xiàn)在的網(wǎng)頁很多都是動態(tài)的泼疑,鼠標(biāo)指向或者點擊網(wǎng)頁中某些元素也會觸發(fā)request動作赘淮,從而使網(wǎng)頁動態(tài)更新部分內(nèi)容血公,這部分內(nèi)容是不能直接從靜態(tài)網(wǎng)頁中獲取的昵仅。這種技術(shù)叫AJAX,不過我不太懂坞笙。這里的問題是我們可能根本不知道網(wǎng)址是什么岩饼,因此需要一些高級的接口,能處理動態(tài)內(nèi)容薛夜。

response是服務(wù)端給客戶端的返回內(nèi)容籍茧。想要獲取靜態(tài)網(wǎng)頁內(nèi)容的話,直接從requeson里取就好了梯澜。

2. 分析網(wǎng)頁源碼

我們想要爬取網(wǎng)頁上的某一部分信息寞冯,需要知道如何能定位到它。這里需要HTML,XPATH的知識晚伙。不知道的可以上w3school 在線教程:http://www.w3school.com.cn

查看網(wǎng)頁源代碼吮龄,鼠標(biāo)指針指向網(wǎng)頁任意地方,或者指向目標(biāo)元素咆疗。右鍵鼠標(biāo)漓帚,在下拉列表選擇“檢查元素”即可。如下是我右鍵“百度一下”所顯示的網(wǎng)頁源代碼午磁,是HTML格式的尝抖,我們可以看到對應(yīng)的HTML代碼。把它提取出來迅皇,我們可能需要div//@[class="head_wrapper"]//input[@type="submit"]的語句昧辽,這是XPATH語法,很好掌握登颓。知道如何分析網(wǎng)頁搅荞,我們又進(jìn)了一步。

3. 網(wǎng)頁基本元素操作

前進(jìn)、后退咕痛、刷新痢甘、打開新選項卡、輸入網(wǎng)址等暇检;

文本框輸入产阱、選擇下拉列表、單選框块仆、復(fù)選框、點擊按鈕等王暗。

我這里需要模擬的操作也就這么多了悔据,對應(yīng)的selenium接口可以參考 http://www.cnblogs.com/Ming8006/p/5727542.html。

4. Selenium介紹

一句話:Selenium是一個web應(yīng)用的自動化測試工具集俗壹。

好多句話:Selenium 誕生于 2004 年科汗,當(dāng)在 ThoughtWorks 工作的 Jason Huggins 在測試一個內(nèi)部應(yīng)用時。作為一個聰明的家伙绷雏,他意識到相對于每次改動都需要手工進(jìn)行測試头滔,他的時間應(yīng)該用得更有價值。他開發(fā)了一個可以驅(qū)動頁面進(jìn)行交互的 Javascript 庫涎显,能讓多瀏覽器自動返回測試結(jié)果坤检。那個庫最終變成了 Selenium 的核心,它是 Selenium RC(遠(yuǎn)程控制)和 Selenium IDE 所有功能的基礎(chǔ)期吓。

實戰(zhàn)練習(xí)

1.分析數(shù)據(jù)獲取的過程

我的數(shù)據(jù)獲取過程如下:

在A頁面輸入查詢語句早歇,點擊submit;瀏覽器自動新開一個頁面讨勤,跳轉(zhuǎn)到新頁面B箭跳,在文本框輸入下載條目的范圍;點擊Export彈出彈窗潭千,然后在下拉列表谱姓、單選框、復(fù)選框做一些選擇刨晴,點擊下載屉来。然后瀏覽器就開始下載文件了。

網(wǎng)頁A

網(wǎng)頁B

2. 爬取過程

?A. 安裝Selenium

Selenium支持多種瀏覽器割捅,我選用google chrome奶躯。下載地址:https://sites.google.com/a/chromium.org/chromedriver/。同時亿驾,當(dāng)然要在python中安裝selenium嘹黔。 命令行輸入pip install senenium 即可安裝。

?B. 配置環(huán)境變量

這一步需要將chromedriver的保存路徑配置到操作系統(tǒng)的環(huán)境變量中,好讓selenium能找到chromedriver儡蔓。windows下配置環(huán)境變量PATH郭蕉,linux或者mac可以選擇配置到 .bash_rc中。配置方法很多喂江,自行百度召锈。

我用的是mac,不知為什么配置了不起作用获询!后來發(fā)現(xiàn)只有在代碼里設(shè)置才能起作用涨岁。

C. 核心代碼(python)

# 設(shè)置下載路徑,將路徑配置到ChromeOptions吉嚣。

chromeptions = webdriver.ChromeOptions()

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

chromeptions.add_experimental_option('prefs', prefs)

# 設(shè)置環(huán)境變量梢薪,啟動瀏覽器。

chromedriver = CHROMEDRIVER_DIR ? ?# 設(shè)置成你自己的路徑

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

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

# 設(shè)置隱形等待時間尝哆,因為點擊后網(wǎng)站一段時間后才能返回內(nèi)容秉撇,如果不等待會報超時異常。

driver.implicitly_wait(IMPLICIT_WAIT_TIME)

# 請求網(wǎng)頁A

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

# 在網(wǎng)頁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()

# ?跳轉(zhuǎn)到新窗口,并將焦點定位到該窗口恒序。

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)

# 獲取到網(wǎng)頁瘦麸。首先獲取返回的總條目數(shù),然后提取文本框輸入下載條目的范圍奸焙,如1-500瞎暑。然后點擊Export。

# 注意:等待頁面加載完成后再計算下載次數(shù)

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()

# 獲取到彈窗与帆。進(jìn)行一些設(shè)置了赌。

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"]')))

# 設(shè)置下載文件的一些配置

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

# 設(shè)置 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

# 設(shè)置 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程序的自動化測試準(zhǔn)備的逢并。另外,爬取過程中要注意屏幕保持打開郭卫。如果進(jìn)入休眠或者屏保砍聊,也會拋出異常的。

B. 模擬網(wǎng)頁操作的時候贰军,網(wǎng)頁跳轉(zhuǎn)是很常見的場景玻蝌。因此要注意網(wǎng)頁響應(yīng)時間。selenium不會等待網(wǎng)頁響應(yīng)完成再繼續(xù)執(zhí)行代碼,它會直接執(zhí)行俯树。二者應(yīng)該是不同的進(jìn)程帘腹。這里可以選擇設(shè)置隱性等待和顯性等待。在其他操作中许饿,隱性等待起決定性作用阳欲,在WebDriverWait..中顯性等待起主要作用,但要注意的是陋率,最長的等待時間取決于兩者之間的大者球化,如果隱性等待時間 > 顯性等待時間,則該句代碼的最長等待時間等于隱性等待時間翘贮。

C. 設(shè)置下載路徑時赊窥,剛開始怎么都不起作用。我懷疑是key “download.default_directory”不對狸页,于是通過查看網(wǎng)頁源代碼,找到了key扯再,依然一樣的芍耘。問題出在其他地方。不過這里提醒了我熄阻,以后在代碼中用字典做相關(guān)的配置時斋竞,可以通過查看源代碼的方式來猜測。

D. 原以為實現(xiàn)整個過程最起碼的兩三天秃殉,因為我真的不懂坝初。從開始學(xué)習(xí)到做完不到一個白天就完成了。估計是因為我動手之前搜了很長時間钾军,反復(fù)比對之后鳄袍,找了個最得心應(yīng)手的工具。

E. 完成后我在github上搜了一圈吏恭,發(fā)現(xiàn)了一個神器https://github.com/voliveirajr/seleniumcrawler拗小。 對于想爬取大量內(nèi)容的朋友,如果還不想浪費時間學(xué)習(xí)太多web應(yīng)用底層的知識樱哼,可以結(jié)合使用Selenium+scrapy哀九。scrapy可以負(fù)責(zé)搜索網(wǎng)頁,selenium負(fù)責(zé)處理每個網(wǎng)頁上的內(nèi)容搅幅,尤其是動態(tài)內(nèi)容阅束。下次我如果有需求,打算用這個思路了茄唐!

F. 分享一句話息裸。“關(guān)于爬蟲,漲經(jīng)驗最快的方式是:學(xué)學(xué)怎么寫網(wǎng)站界牡,你知道網(wǎng)站是什么發(fā)請求的簿寂,就知道怎么爬網(wǎng)站了!” 很簡單吧宿亡,不過這么簡單的一句話給我很大的啟發(fā)常遂。之前就是感覺太難,一直停留在scrapy爬取靜態(tài)網(wǎng)頁的水平挽荠。而且像cookies之類的技術(shù)也看了克胳,看一次忘一次。現(xiàn)在看來圈匆,還是因為沒有把網(wǎng)站的整體流程梳理清楚漠另。另一方面,也是畏懼那些繁雜的網(wǎng)站技術(shù)名詞跃赚。其實只要上網(wǎng)查查相關(guān)的概念怎么回事笆搓,慢慢就打通了。

G. 最后纬傲,完全不懂編程的人可以用一些可視化的爬蟲工具满败,這里有一些介紹:https://www.sdk.cn/news/4801。懂編程的且想要高效率的就需要參考其他工具了叹括。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末算墨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子汁雷,更是在濱河造成了極大的恐慌净嘀,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侠讯,死亡現(xiàn)場離奇詭異挖藏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)继低,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進(jìn)店門熬苍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人袁翁,你說我怎么就攤上這事柴底。” “怎么了粱胜?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵柄驻,是天一觀的道長。 經(jīng)常有香客問我焙压,道長鸿脓,這世上最難降的妖魔是什么抑钟? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮野哭,結(jié)果婚禮上在塔,老公的妹妹穿的比我還像新娘。我一直安慰自己拨黔,他們只是感情好蛔溃,可當(dāng)我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著篱蝇,像睡著了一般贺待。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上零截,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天麸塞,我揣著相機(jī)與錄音,去河邊找鬼涧衙。 笑死哪工,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的弧哎。 我是一名探鬼主播正勒,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼傻铣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起祥绞,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤非洲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蜕径,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體两踏,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年兜喻,在試婚紗的時候發(fā)現(xiàn)自己被綠了梦染。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡朴皆,死狀恐怖帕识,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情遂铡,我是刑警寧澤肮疗,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站扒接,受9級特大地震影響伪货,放射性物質(zhì)發(fā)生泄漏们衙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一碱呼、第九天 我趴在偏房一處隱蔽的房頂上張望蒙挑。 院中可真熱鬧,春花似錦愚臀、人聲如沸忆蚀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜓谋。三九已至,卻和暖如春炭分,著一層夾襖步出監(jiān)牢的瞬間桃焕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工捧毛, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留观堂,地道東北人。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓呀忧,卻偏偏與公主長得像师痕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子而账,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容