標籤:開啟 doc 對象 選擇 根據 圖片 ima 簽名 blog
前幾天有位讀者問我一個爬蟲的問題,就是在爬去百度貼吧首頁的熱門動態下面的圖片的時候,爬取的圖片總是爬取不完整,比首頁看到的少。原因他也大概分析了下,就是後面的圖片是動態載入的。他的問題就是這部分動態載入的圖片該怎麼爬取到。
分析
他的代碼比較簡單,主要有以下的步驟:使用BeautifulSoup
庫,開啟百度貼吧的首頁地址,再解析得到id
為new_list
標籤底下的img
標籤,最後將img
標籤的圖片儲存下來。
headers = { ‘User-Agent‘:‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36‘}data=requests.get("https://tieba.baidu.com/index.html",headers=headers)html=BeautifulSoup(data.text,‘lxml‘)
前面提到過,有部分圖片是動態載入的,那麼首先我們得弄清楚,這部分圖片是怎麼動態載入的。在瀏覽器中開啟百度貼吧的首頁,可以明顯的看到,在往下滾動捲軸的時候,當滾動到底部的時候,捲軸縮短了,並向上移動了一段距離。這個現象也正是有DOM
元素動態添加到了html
文檔的一個表現。動態載入資料無非就是ajax
請求,而ajax
本質上就是XMLHttpRequest
請求(簡稱xhr
)。在Google瀏覽器中,我們可以通過開發人員工具的network
面板來監測xhr請求。
剛開啟首頁時的xhr
請求,這裡的請求都和要爬取的圖片無關。
捲軸向下第1次滾動到底部,這裡請求的是第20-40
條熱門動態,包含要爬取圖片。
捲軸向下第2次滾動到底部,這裡請求的是第40-60
條熱門動態,包含要爬取圖片。並且返回的的has_more:false
表明沒有跟多資料了。
捲軸向下第3次滾動到底部,再無xhr
請求。
解決方案
根據上面的分析,我們已經明白,單純使用BeautifulSoup
進行爬蟲的時候,只能爬取到1-20
條熱門動態裡面的圖片。為了爬取到完整的熱門動態裡面的圖片,我們則需要類比瀏覽器的捲軸滾動,讓網頁去觸發xhr
請求更多的熱門動態。
在python中,如果需要類比瀏覽器的行為,可以使用selenium
庫。selenium
庫是一個自動化測試架構,可以用來類比測試瀏覽器的各種行為,這裡我們使用它來類比瀏覽器開啟百度貼吧的首頁,並類比捲軸向下滾動到底部的操作。
安裝
pip install selenium
下載瀏覽器驅動
Firefox瀏覽器驅動,其是:https://github.com/mozilla/geckodriver/releases
Google瀏覽器驅動,其是:http://chromedriver.storage.googleapis.com/index.html?path=2.33/
opera瀏覽器驅動,其是:https://github.com/operasoftware/operachromiumdriver/releases
對照自己電腦安裝的瀏覽器和對應的版本,分別從上面的地址下載驅動檔案,也可以從我的github項目中統一下載以上幾個驅動(地址:https://github.com/Sesshoumaru/attachments/tree/master/Selenium%20WebDriver)。下載解壓後,將所在的目錄添加系統的環境變數中。當然你也可以將下載下來的驅動放到python安裝目錄的lib
目錄中,因為它本身已經存在於環境變數(我就是這麼乾的)。
使用python代碼類比瀏覽器行為
要使用selenium
先需要定義一個具體browser
對象,這裡就定義的時候就看你電腦安裝的具體瀏覽器和安裝的哪個瀏覽器的驅動。這裡以Firefox瀏覽器為例:
from selenium import webdriverbrowser = webdriver.Firefox()
再類比開啟貼吧首頁:
browser.get("https://tieba.baidu.com/index.html")
再類比捲軸滾動到底部
for i in range(1, 5): browser.execute_script(‘window.scrollTo(0, document.body.scrollHeight)‘) time.sleep(1)
最後再使用BeautifulSoup
,解析圖片標籤:
html = BeautifulSoup(browser.page_source, "lxml")imgs = html.select("#new_list li img")
幾個注意點
必須安裝瀏覽器和瀏覽器驅動,並且瀏覽器和瀏覽器驅動要配到
即如果使用Google瀏覽器類比網頁行為,則需要下載Google瀏覽器驅動;如果使用Firefox瀏覽器類比網頁行為,則需要下載Firefox瀏覽器驅動
瀏覽器驅動所在的目錄要在環境變數中,或者定義瀏覽器browser
的時候指定驅動的路徑
selenium更多用法尋找元素
from selenium import webdriverbrowser = webdriver.Firefox()browser.get("https://tieba.baidu.com/index.html")new_list = browser.find_element_by_id(‘new_list‘)user_name = browser.find_element_by_name (‘user_name‘)active = browser.find_element_by_class_name (‘active‘)p = browser.find_element_by_tag_name (‘p‘)# find_element_by_name 通過name尋找單個元素# find_element_by_xpath 通過xpath尋找單個元素# find_element_by_link_text 通過連結尋找單個元素# find_element_by_partial_link_text 通過部分連結尋找單個元素# find_element_by_tag_name 通過標籤名稱尋找單個元素# find_element_by_class_name 通過類名尋找單個元素# find_element_by_css_selector 通過css選擇武器尋找單個元素# find_elements_by_name 通過name尋找多個元素# find_elements_by_xpath 通過xpath尋找多個元素# find_elements_by_link_text 通過連結尋找多個元素# find_elements_by_partial_link_text 通過部分連結尋找多個元素# find_elements_by_tag_name 通過標籤名稱尋找多個元素# find_elements_by_class_name 通過類名尋找多個元素# find_elements_by_css_selector 通過css選擇武器尋找多個元素
擷取元素資訊
btn_more = browser.find_element_by_id(‘btn_more‘)print(btn_more.get_attribute(‘class‘)) # 擷取屬性print(btn_more.get_attribute(‘href‘)) # 擷取屬性print(btn_more.text) # 擷取文本值
元素互動操作
btn_more = browser.find_element_by_id(‘btn_more‘)btn_more.click() # 類比點擊,可以類比點擊載入更多input_search = browser.find_element(By.ID,‘q‘)input_search.clear() # 清空輸入
執行JavaScript
# 執行JavaScript指令碼browser.execute_script(‘window.scrollTo(0, document.body.scrollHeight)‘)browser.execute_script(‘alert("To Bottom")‘)
python爬蟲:使用Selenium類比瀏覽器行為