1. 程式人生 > >Python3爬蟲-selenium爬取百度文庫

Python3爬蟲-selenium爬取百度文庫

      這是筆者爬取的第一個動態載入的網頁,使用的IDE是Pycharm,選擇的是百度文庫的一篇16年六級卷子的文件。若直接使用requests模組去得到網頁原始碼,會發現所得非所見,不能獲取到文件中的內容。看了網上數篇博文的思路,最後還是嘗試了使用selenium模組模擬安卓裝置使用chrome瀏覽器訪問,這樣訪問可以獲得網頁的完整原始碼。這篇文件預設載入了不到20%,點選“繼續閱讀”字樣,之後內容載入到20%,這時若想要閱讀更多內容需要點選的字樣變成了“點選載入更多”,連續點選“點選載入更多”直到所有文件內容都已載入,此時再使用selenium的page_source方法獲取完整的網頁原始碼,得到原始碼後的操作就輕鬆了很多,使用BeautifulSoup模組從原始碼中獲取需要的文件內容,之後用python-docx模組將獲取的文件內容存到本地文件中。雖然程式碼不長,但還是踩到了不少坑,先放程式碼吧,然後再填坑。

 

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import lxml
from bs4 import  BeautifulSoup
import time
import docx
import re
from selenium.webdriver.common.action_chains import ActionChains
from selenium import webdriver

#模擬移動裝置使用chrome開啟指定頁面
options = webdriver.ChromeOptions()
options.add_argument('user-agent="Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19"')
driver = webdriver.Chrome(r"C:\Users\hhp\AppData\Local\Google\Chrome\Application\chromedriver.exe",chrome_options=options)
driver.get('https://wenku.baidu.com/view/83dd3c6f6bec0975f565e29f.html')

#模擬滑鼠點選“繼續閱讀”
time.sleep(2)
pos = driver.find_element_by_xpath("//div[@class='foldpagewg-root']")
ActionChains(driver).move_to_element(pos).click(pos).perform()

#模擬滑鼠點選“點選載入更多“
pos2 = driver.find_element_by_xpath("//div[@class='btns-warp']")
pos3 = driver.find_element_by_xpath("//div[@class='pagerwg-button']")

loop = 1
while loop <= 5:
    time.sleep(1)
    ActionChains(driver).move_to_element(pos2).perform()
    ActionChains(driver).click(pos3).perform()
    loop = loop + 1

#從得到的完整頁面原始碼提取資料並存儲
html = driver.page_source
bf = BeautifulSoup(html,'lxml')
get_docx_name = bf.find(class_='doc-title').get_text()
docx_name = re.sub('\s','',get_docx_name)+'.docx'
pages = bf.find_all(class_='content singlePage wk-container')

file = docx.Document()
with open('2016-6-I-six.txt', 'w',encoding = 'utf-8') as f:
    for page in pages:
        para = page.find_all(class_ = 'txt')
        for p in para:
            text = p.get_text()
            f.write(text+'\n')
            file.add_paragraph(text)
file.save(docx_name)

 

使用到的模組

BeautifulSoup模組用來從html中提取資料,這裡使用lxml HTML解析器,引入了lxml模組

time模組在程式碼中使用到延時函式,這裡就是為了暫緩一下程式的執行,能更清楚的看到chrome瀏覽器被呼叫後整個操作流程,可有可無

re模組用到了sub函式處理字串

docx模組踩到了連環坑,安裝python-docx模組就好了

selenium模組用來操縱chrome瀏覽器,當然其功能不止於chrome

 

驅動問題

使用selenium操縱chrome瀏覽器先確定要有chromedriver驅動,沒有的話會報錯,可以從

http://npm.taobao.org/mirrors/chromedriver/下載驅動

下載時要注意自己瀏覽器的版本,驅動與瀏覽器版本對應關係可以在http://npm.taobao.org/mirrors/chromedriver/2.40/notes.txt中找到,截圖如下。

  如果不清楚自己瀏覽器的版本,可以在chrome位址列中輸入 chrome://version

開啟的介面如圖,筆者的chrome是v67,沒有更新到最新版,下載驅動要看好版本間對應關係

 

下載好的chromedriver.exe驅動要放置到自己安裝的chrome瀏覽器的安裝目錄下,筆者驅動的路徑是

C:\Users\hhp\AppData\Local\Google\Chrome\Application\chromedriver.exe

設定環境變數

通過 我的電腦-屬性-高階系統設定-高階-環境變數-Path  新增chromedriver.exe所在位置

 

具體程式碼

  • 開啟網頁

 

options = webdriver.ChromeOptions()


設定啟動chrome時的選項,這裡的用途是設定user-agent選項模擬移動裝置

driver = webdriver.Chrome(r"C:\Users\hhp\AppData\Local\Google\Chrome\Application\chromedriver.exe",chrome_options=options)
driver.get('https://wenku.baidu.com/view/83dd3c6f6bec0975f565e29f.html')

這兩句會開啟chrome瀏覽器並開啟指定的那篇文件的頁面

筆者這裡webdriver.chrome()的寫法是沒有配置chromedriver的環境變數,其中加的r是為了規避反斜槓的轉義

如果配置過環境變數,可以寫成

webdriver.Chrome(chrome_options=options)

如果你在設定環境變數時IDE是正在執行的,需要重啟IDE後設置的環境變數才生效,否則直接執行程式會報錯:

selenium.common.exceptions.WebDriverException: Message: 'ChromeDriver executable needs to be available in the path.

 

 

  • 模擬滑鼠獲取完整網頁
pos = driver.find_element_by_xpath("//div[@class='foldpagewg-root']")

如上圖,通過xpath的相對定位方式選擇具有'foldpagewg-root'樣式的div標籤,在此div應用到的區域內,點選滑鼠均可載入更多,如圖左半部分陰影所示。關於xpath方法查詢元素,筆者水平很有限,還不能作很好的總結,大家可以查閱網上的詳細講解。

這裡只用到了相對定位,即'//'開頭,與之對應便有絕對定位。可以看如下例子

如果要定位到圈中的位置,絕對定位以'/'表示,且從根節點開始,寫法是/html/body/div[@id='BAIDU_DUP_fp_wrapper']

相對定位更為簡短 //div[@id='BAIDU_DUP_fp_wrapper']

 

ActionChains(driver).move_to_element(pos).click(pos).perform()

是模擬滑鼠操作,之後可以看到文件載入到20%

其中的move_to_element()將滑鼠移動到之前定位的pos位置,click()函式模擬滑鼠左鍵單擊,perform()將操作執行

 

 

pos2 = driver.find_element_by_xpath("//div[@class='btns-warp']")
pos3 = driver.find_element_by_xpath("//div[@class='pagerwg-button']")

loop = 1
while loop <= 5:
    time.sleep(1)
    ActionChains(driver).move_to_element(pos2).perform()
    ActionChains(driver).click(pos3).perform()
    loop = loop + 1

 

在內容載入到20%之後,想要載入更多需要點選“點選載入更多”,上面的pos2,pos3的定位就是為此

這裡也遇到了小問題,一開始move_to_element()是直接移動到pagerw-button位置,之後的click()也是點選這裡,但程式碼執行起來並沒有載入更多,觀察chrome的操作過程發現,這樣的滑鼠移動方式並沒有將頁面下拉到足以顯示出“點選載入更多”字樣,也就是說其被遮擋了,click()點選操作錯誤地指向網頁的其他元素。move_to_element的效果類似於用滑鼠滾輪下滑網頁,把網頁滑動到一個指定的位置便停止,修改程式碼為滑鼠移動到div class='btns-warp'位置後,這時的網頁中點選載入更多不再被遮擋,再用click()執行點選可以正常完成。這裡迴圈五次是為了使網頁內容全部載入完畢。

 

  • 從獲得的完整網頁提取資料
html = driver.page_source
bf = BeautifulSoup(html,'lxml')

 

經過上述模擬滑鼠點選操作獲得完整網頁原始碼後,剩下的操作就更為簡單,page_source獲得網頁原始碼,然後使用BeautifulSoup模組從html原始碼中提取資料。

get_docx_name = bf.find(class_='doc-title').get_text()

這句是為了獲得文件名,使用BeautifulSoup的find方法找到包含文件名的div標籤

 

docx_name = re.sub('\s','',get_docx_name)+'.docx'

sub()將get_docx_name字串中的所有不可顯字元替換為 '',效果就是去除了這些不可顯字元,如空格,換行符

 

pages = bf.find_all(class_='content singlePage wk-container')

這句從網頁程式碼中選取包含文件每一頁的部分

 

file = docx.Document()
with open('2016-6-I-six.txt', 'w',encoding = 'utf-8') as f:
    for page in pages:
        para = page.find_all(class_ = 'txt')
        for p in para:
            text = p.get_text()
            f.write(text+'\n')
            file.add_paragraph(text)
file.save(docx_name)

最後這部分程式碼提取文字的文字內容,儲存到本地,這裡同時儲存為了docx和txt檔案,這裡用到的檔案操作較為簡單,很容易上手。

f.write(text+'\n')中的+'\n'是為了換行,否則存為的txt檔案很亂。而docx模組還有很多很多功能,這裡也只是用到了最為基礎的插入文字。

page.find_all(class_='txt')是獲取到每頁中的所有段落,下圖有對應關係,函式返回值型別是列表

所以有了之後的for p in pages迴圈,p.get_text()提取到真正的文字

file.save()儲存檔案,路徑可以自己指定,這裡只寫了一個docx_name,會儲存到預設路徑,即和這份程式碼同一路徑,例如筆者這份程式碼test.py路徑為G:\Pycharm\test.py 檔案預設會儲存到G:\Pycharm,也可以自己指定,比如file.save('C:test_docx.docx')

程式執行後得:

總結

        這是我的第一篇部落格,第一篇的內容選擇了python爬蟲,自己水平很有限,寫起來還是挺有壓力的。這裡爬取的方法也只是設法獲得包含有文件文字內容的html原始碼,從中提取出文件內容後自己再生成檔案,不過如果充分利用docx模組可以對得到的資料進行自由排布。網上很多爬蟲文章的程式碼都失效了,這篇文章權當提供一份可以實際操作的程式碼去嘗試。當然隨著時間流逝,這份程式碼也會失效,如果以後有了好的思路,筆者會對這篇文章做些增刪查改,或者推倒重來。最後添上一些文件或者部落格的連結。

 

 

參考的文章:

Selenium 之訂製啟動Chrome的選項(Options)

Beautiful Soup 4.4.0 文件

Selenium-Python中文文件

python-docx

Selenium之Action Chains類

Python3網路爬蟲(九):使用Selenium爬取百度文庫word文章