Python爬蟲初探 - selenium+beautifulsoup4+chromedriver爬取需要登錄的網頁信息
目標
之前的自動答復機器人需要從一個內部網頁上獲取的消息用於回復一些問題,但是沒有對應的查詢api,於是想到了用腳本模擬瀏覽器訪問網站爬取內容返回給用戶。詳細介紹了第一次探索python爬蟲的坑。
準備工作
requests模塊向網站發送http請求,BeautifulSoup模塊來從靜態HTML文本中提取我們想要的數據,更高級的,對於動態加載頁面我們需要用webdriver去模擬真實的網頁訪問,並解析內容。
推薦使用Anaconda 這個科學計算版本,主要是因為它自帶一個包管理工具,可以解決有些包安裝錯誤的問題。
- 安裝requests(anaconda自帶),selenium,beautifulsoup4,方法為
pip install selenium conda install beautifulsoup4 conda install lxml
使用Python3.5 的童鞋們直接使用pip install beautifulsoup4安裝會報錯(所以才推薦使用Anaconda版本),安裝教程看這裏。
你可能需要安裝lxml,這是一個解析器,BeautifulSoup可以使用它來解析HTML,然後提取內容。
如果不安裝lxml,則BeautifulSoup會使用Python內置的解析器對文檔進行解析。之所以使用lxml,是因為它速度快。
參考Python爬蟲小白入門(三)BeautifulSoup庫
https://www.cnblogs.com/Albert-Lee/p/6232745.html
關於webdriver的搭配網上一些舊帖子都說的是selenium+PhantomJS,但是目前selenium已經不再支持PhantomJS(如果使用了會報錯syntax error,坑了很久才知道這個消息),只能使用chrome或者firefox的對應驅動,這裏我們使用chromedriver,你也可以使用firefoxdriver。接下來說說chromedriver的安裝
- 從http://chromedriver.storage.googleapis.com/index.html網址中下載與本機chrome瀏覽器對應的chromedriver驅動程序,chrome版本可以打開瀏覽器右上角
驅動版本對應參考如下,轉自chromedriver與chrome各版本及下載地址
- 將下載的chromedriver解壓到chrome安裝目錄(右鍵chrome快捷方式查看屬性),再將chrome安裝目錄添加到電腦的Path環境變量中,並手動cmd刷新下path信息,相關操作百度一搜一大堆
開始工作
程序根據用戶輸入,在一個引導頁匹配查找對應的產品網址後綴,添加到url鏈接的請求參數部分的?product=後面,後續將訪問新的網址
import的模塊
首先介紹下import的模塊
import requests#發起靜態url請求 from bs4 import BeautifulSoup#BeautifulSoup解析 import re#正則匹配 from selenium import webdriver#下面是webdriver所需 from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.desired_capabilities import DesiredCapabilities import time#動態加載頁面需要延時再獲取信息
匹配搜索
定義了一個匹配搜索的函數,如果用戶輸入的字符(’a‘)被包含在搜索列表([’bat‘,’link‘,’you‘])中某項之中(比如‘a’被’bat‘包含),則返回包含的項(‘bat‘),搜不到就返回’None‘,使用re正則加快匹配
1 def branchFinder(userInput, collection): 2 regex = re.compile(userInput) # Compiles a regex. 3 for item in collection: 4 match = regex.search(item) # Checks if the current item matches the regex. 5 if match: 6 return item 7 return ‘None‘
如果使用模糊搜索參考http://www.mamicode.com/info-detail-1601799.html
獲取並解析靜態頁面
使用requests.get訪問靜態頁面,使用BeautifulSoup處理頁面
1 url1 = ‘https://www.xxxx.com/?&product=‘ 2 3 r = requests.get(url1, cookies = cookies, headers = headers) 4 # with open(‘main.html‘, ‘wb+‘) as f: 5 # f.write(r.content) 6 7 soup = BeautifulSoup(r.content, ‘lxml‘) #聲明BeautifulSoup對象 8 findResult = soup.find_all(‘option‘) #在頁面查找所有的option標簽 9 optionList = []#option所有選項的value參數列表 10 for i in range(1,len(findResult)):#第一個option是默認selected的選項,為空,所以這裏沒有添加進列表 11 optionList.append(findResult[i][‘value‘]) 12 # print(optionList) 13 #已獲取主界面的value列表 14 15 16 #根據關鍵字查找對應的branch選項,生成新的訪問鏈接 17 branch = branchFinder(userInput,optionList) 18 if (branch == ‘None‘): 19 return ‘Not Found. Please check your input.‘ #為了實現return,實際上這些代碼整個寫在一個函數裏 20 print(branch+‘\n‘) 21 url2 = url1 + branchFinder(userInput,optionList)#新的訪問鏈接
其中headers是你訪問頁面的瀏覽器信息,cookies包含了登錄信息,用於在網頁需要登錄的情況下搞定訪問權限,示例如下
headers = {‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36‘} cookies = {‘cookie‘: ‘has_js=1; xxxxx=yyyyy‘}
查看以上信息的方式為瀏覽器訪問url1的鏈接,登錄後F12打開調試器,按照下圖尋找Name的第一個參數,找到橢圓圈出來的cookies和headers,填入上面的示例
關於BeautifulSoup對於網頁信息的獲取和處理函數參考Python爬蟲小白入門(三)BeautifulSoup庫,至此我們已經完成了靜態爬取網頁信息的嘗試,當我嘗試如法炮制訪問url2的時候,使用BeautifulSoup一直獲取不到我想要的表格中的數據,查找<table>標簽後,裏面只有<thead>沒有<tbody>,查看requests獲取的網頁信息才發現根本沒有tbody,在瀏覽器中訪問url2,打開F12,發現表格使用的是datatable,因為之前做過使用datatable的項目,所以覺得這裏可能是動態加載的tbody中的數據,靜態訪問是獲取不到表格數據的,這就需要動態加載了。
動態加載處理頁面
經歷了selenium+PhantomJS的失敗嘗試後,我轉而使用selenium+headless chrome,這也是在運行PhantomJS相關代碼後編譯器提示才知道的。
關於driver對於頁面的處理操作非常方便,不僅可以查找,還可以模擬click等功能,詳見WebDriver--定位元素的8種方式和【Selenium2+Python】常用操作和webdriver(python)學習筆記一等等
1 dcap = dict(DesiredCapabilities.PHANTOMJS) #設置useragent,實際上只是使用了phantomjs的參數,各位可以ctrl+鼠標點進去定義查看具體參數 2 dcap[‘phantomjs.page.settings.userAgent‘] = (headers[‘User-Agent‘]) #根據需要設置具體的瀏覽器信息 3 4 chrome_options = Options() 5 chrome_options.add_argument(‘--no-sandbox‘)#解決DevToolsActivePort文件不存在的報錯 6 chrome_options.add_argument(‘window-size=1920x3000‘) #指定瀏覽器分辨率 7 chrome_options.add_argument(‘--disable-gpu‘) #谷歌文檔提到需要加上這個屬性來規避bug,否則會提示gpu開啟失敗 8 chrome_options.add_argument(‘--hide-scrollbars‘) #隱藏滾動條, 應對一些特殊頁面 9 chrome_options.add_argument(‘blink-settings=imagesEnabled=false‘) #不加載圖片, 提升速度 10 chrome_options.add_argument(‘--headless‘) #瀏覽器不提供可視化頁面. linux下如果系統不支持可視化不加這條會啟動失敗,windows如果不加這條會
啟動瀏覽器GUI,並且不會返回句柄,只會等待操作,後面的代碼不會執行了 11 chrome_options.binary_location = r"C:/Program Files (x86)/Google/Chrome/Application/chrome.exe" #手動指定使用的瀏覽器位置 12 13 # driver=webdriver.Chrome(chrome_options=chrome_options) 14 # driver.get(‘https://www.baidu.com‘) 15 # print(‘hao123‘ in driver.page_source) 16 driver = webdriver.Chrome(chrome_options=chrome_options,desired_capabilities=dcap)#封裝瀏覽器信息 17 # driver = webdriver.Chrome(desired_capabilities=dcap) 18 driver.get(url2)# 訪問鏈接 19 # 添加cookies,註意和之前的格式不一樣,之前cookies的格式是xxxxx=yyyyy,這裏name對應的是=之前的xxxxx,value對應的是yyyyy 20 driver.add_cookie({‘name‘ : ‘xxxxx‘, ‘value‘ : ‘yyyyy‘}) 21 driver.refresh()#重新加載以登錄 22 driver.implicitly_wait(1)#等待1s加載數據,需要根據感覺調整時長,如果1s不夠就要增加時間,詳情參考後面的for循環等待加載數據 23 time.sleep(0.1) 24 #顯示Product summary界面 25 print(‘Product summary.\n‘) 26 #點擊最新的Build鏈接 27 driver.find_element_by_tag_name("tbody").find_element_by_tag_name("a").click()#可以順蔓摸瓜查找一個標簽下的其他標簽,不論是一個標簽還是標簽集 28 #已進入Build Viewer界面 29 print(‘Build Viewer.\n‘) 30 #點擊Tests 31 driver.find_element_by_id(‘1‘).click()#根據id查找並點擊 32 print(driver.find_element_by_class_name(‘table-responsive‘).text)#打印應該是空的,因為還沒獲取到數據 33 result = ‘‘ 34 for i in range(20):#循環加載20s,獲取表格數據,由於find也需要時間,實際上加載不止20s 35 driver.implicitly_wait(1)#等待加載數據 36 result = driver.find_element_by_class_name(‘table-responsive‘).text 37 if(result == ‘‘):#循環加載數據,直到非空 38 print( ‘Waiting ‘+ str(i+1) + ‘s...‘) 39 else: 40 break 41 42 driver.quit()#退出瀏覽器
- 最開始我driver.implicitly_wait(1)加載的時間很短,但是也能獲取到頁面內容,因為我是設置的斷點調試的!所以等待加載的時間比我設置的長多了!退出debug模式直接run的時候,有時候設置為5s仍然獲取不到數據,發現這個坑的時候簡直驚呼!不過還好我們可以使用循環等待來判斷什麽時候加載數據完畢。
- 之前沒有設置headless,使用cmd嘗試可以打開chrome瀏覽器GUI,但是使用vscode打不開GUI,才知道需要管理員權限,於是使用管理員方式打開vscode即可
輸出結果
aiodnwebg DevTools listening on ws://127.0.0.1:12133/devtools/browser/xxxx Product summary. Build Viewer. Waiting 1s... Waiting 2s... Waiting 3s... ID Job 123 aaa 245 bbb
完整代碼
1 import requests 2 from bs4 import BeautifulSoup 3 import re 4 from selenium import webdriver 5 from selenium.webdriver.chrome.options import Options 6 from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 7 import time 8 9 ###################User Input########################## 10 userInput = ‘=====your input======‘ 11 12 headers = {‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36‘} 13 14 cookies = {‘cookie‘: ‘has_js=1; xxxxx=yyyyy‘} 15 ###################User Input########################## 16 17 18 def branchFinder(userInput, collection): 19 regex = re.compile(userInput) # Compiles a regex. 20 for item in collection: 21 match = regex.search(item) # Checks if the current item matches the regex. 22 if match: 23 return item 24 return ‘None‘ 25 26 def getResult(userInput): 27 url1 = ‘https://www.xxx.com/?&product=‘ 28 29 r = requests.get(url1, cookies = cookies, headers = headers) 30 # with open(‘main.html‘, ‘wb+‘) as f: 31 # f.write(r.content) 32 33 soup = BeautifulSoup(r.content, ‘lxml‘) #聲明BeautifulSoup對象 34 findResult = soup.find_all(‘option‘) #查找option標簽 35 optionList = [] 36 for i in range(1,len(findResult)): 37 optionList.append(findResult[i][‘value‘]) 38 # print(optionList) 39 #已獲取主界面的value列表 40 41 42 #根據關鍵字查找對應的branch,生成新的訪問鏈接 43 branch = branchFinder(userInput,optionList) 44 if (branch == ‘None‘): 45 return ‘Not Found. Please check your input.‘ 46 print(branch+‘\n‘) 47 url2 = url1 + branchFinder(userInput,optionList) 48 dcap = dict(DesiredCapabilities.PHANTOMJS) #設置useragent 49 dcap[‘phantomjs.page.settings.userAgent‘] = (headers[‘User-Agent‘]) #根據需要設置具體的瀏覽器信息 50 51 chrome_options = Options() 52 chrome_options.add_argument(‘--no-sandbox‘)#解決DevToolsActivePort文件不存在的報錯 53 chrome_options.add_argument(‘window-size=1920x3000‘) #指定瀏覽器分辨率 54 chrome_options.add_argument(‘--disable-gpu‘) #谷歌文檔提到需要加上這個屬性來規避bug 55 chrome_options.add_argument(‘--hide-scrollbars‘) #隱藏滾動條, 應對一些特殊頁面 56 chrome_options.add_argument(‘blink-settings=imagesEnabled=false‘) #不加載圖片, 提升速度 57 chrome_options.add_argument(‘--headless‘) #瀏覽器不提供可視化頁面. linux下如果系統不支持可視化不加這條會啟動失敗 58 chrome_options.binary_location = r"C:/Program Files (x86)/Google/Chrome/Application/chrome.exe" #手動指定使用的瀏覽器位置 59 60 # driver=webdriver.Chrome(chrome_options=chrome_options) 61 # driver.get(‘https://www.baidu.com‘) 62 # print(‘hao123‘ in driver.page_source) 63 driver = webdriver.Chrome(chrome_options=chrome_options,desired_capabilities=dcap)#封裝瀏覽器信息 64 # driver = webdriver.Chrome(desired_capabilities=dcap) 65 driver.get(url2) 66 67 driver.add_cookie({‘name‘ : ‘xxxxx‘, ‘value‘ : ‘yyyyy‘}) 68 driver.refresh()#重新加載以登錄 69 driver.implicitly_wait(1)#等待加載數據 70 time.sleep(0.1) 71 #顯示Product summary界面 72 print(‘Product summary.\n‘) 73 #點擊最新的Build鏈接 74 driver.find_element_by_tag_name("tbody").find_element_by_tag_name("a").click() 75 #已進入Build Viewer界面 76 print(‘Build Viewer.\n‘) 77 #點擊Tests 78 driver.find_element_by_id(‘1‘).click() 79 print(driver.find_element_by_class_name(‘table-responsive‘).text) 80 result = ‘‘ 81 for i in range(20): 82 driver.implicitly_wait(1)#等待加載數據 83 result = driver.find_element_by_class_name(‘table-responsive‘).text 84 if(result == ‘‘): 85 print( ‘Waiting ‘+ str(i+1) + ‘s...‘) 86 else: 87 break 88 driver.quit() 89 return result 90 91 finalResult = getResult(userInput) 92 print(finalResult)View Code
後記
一個下午做完這些,才知道有個東西叫Scrapy,= =之後試一試
需要管理員權限 [Xūyào guǎnlǐ yuán quánxiàn] Requires administrator privilegesPython爬蟲初探 - selenium+beautifulsoup4+chromedriver爬取需要登錄的網頁信息