1. 程式人生 > 實用技巧 >python+selenium+bs4爬取百度文庫內文字 && selenium 元素可以定位到,但是無法點選問題 && pycharm多行縮排、左移

python+selenium+bs4爬取百度文庫內文字 && selenium 元素可以定位到,但是無法點選問題 && pycharm多行縮排、左移

先說一下可能用到的一些python知識

一、python中使用的是unicode編碼, 而日常文字使用各類編碼如:gbk utf-8 等等所以使用python進行文字讀寫操作時候經常會出現各種錯誤, 一般都是操作時沒有進行轉碼操作.而轉碼則需要decode(解碼)和encode(編碼)方法.

如:
str1.decode(‘gbk’), 表示將gbk編碼的字串‘str1’轉換成unicode編碼.
str2.encode(‘gbk’), 表示將unicode編碼的字串‘str2’轉換gbk編碼.

二、寫入資料的時候報錯程式直接停止,這就不得不重視“Python UnicodeEncodeError: 'gbk' codec can't encode character ”解決方法

將網路資料流寫入檔案時時,我們會遇到幾個編碼:

1: #encoding='XXX' 這裡(也就是python檔案第一行的內容)的編碼是指該python指令碼檔案本身的編碼,無關緊要。只要XXX和檔案本身的編碼相同就行了。 比如notepad++ "格式"選單裡面裡可以設定各種編碼,這時需要保證該選單裡設定的編碼和encoding XXX相同就行了,不同的話會報錯

2:網路資料流的編碼 比如獲取網頁,那麼網路資料流的編碼就是網頁的編碼。需要使用decode解碼成unicode編碼。

3:目標檔案的編碼 要將網路資料流的編碼寫入到新檔案,那麼我麼需要指定新檔案的編碼。在windows下面,新檔案的預設編碼是gbk,這樣的話,python直譯器會用gbk編碼去解析我們的網路資料流txt,然而txt此時已經是decode過的unicode編碼,這樣的話就會導致解析不了,出現上述問題。 解決的辦法就是,改變目標檔案的編碼:

f = open("out.html","w",encoding='utf-8')  

三、pycharm縮排

1、pycharm使多行程式碼同時縮排、左移

滑鼠選中多行程式碼後,按下Tab鍵,一次縮排四個字元

2、pycharm使多行程式碼同時左移

滑鼠選中多行程式碼後,同時按住shift+Tab鍵,一次左移四個字元

四、time.sleep(t)

引數:t -- 推遲執行的秒數。

五、selenium 元素可以定位到,但是無法點選問題

描述:頁面元素可以定位到,但是無法點選click。元素可能被一個透明div覆蓋了
解決方案:
1.在執行click之前多休眠幾秒
2.確認自己的元素是否定位正確,是否有id,name,class相同的元素,加下劃線的是遮擋的div確定它的位置判斷他的z_index是否大於你要點選元素的z_index

3.用Enter鍵代替click

4、將頁面拖拽到要點選的元素位置,例如百度文庫點選繼續閱讀展示全部內容(程式碼如下)

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome('D:/chromedriver.exe')
driver.get("https://wenku.baidu.com/view/aa31a84bcf84b9d528ea7a2c.html")
page = driver.find_element_by_xpath("//*[@id='html-reader-go-more']/div[2]/div[1]/span/span[2]")
driver.execute_script('arguments[0].scrollIntoView();', page) #拖動到可見的元素去
driver.find_element_by_xpath("//*[@id='html-reader-go-more']/div[2]/div[1]/p").click()

六、爬取百度文庫連線:https://wenku.baidu.com/view/df34290a763231126edb11f9.html

原本我就沒有想著要去用自動化工具去爬取,本來想著取用requests模擬請求,頂多就是麻煩一下弄弄js,但是我一看百度文庫它的請求頭

找這個檔案找了半天,主要是它的文字不是連續的,我剛開始大致一看都沒有找到。我還以為怎麼了(翻車現場)。。。弄了半天可以確定0.png?這樣型別的傳遞的是文庫的照片,0.json傳遞的是文庫的文字

但是這個請求頭的url太長了,,突然就不想用requests模擬請求了

那就用selenium自動化工具+bs4解析頁面,如果沒有安裝python的selenium庫和selenium對應的瀏覽器驅動可以看一下:安裝python的selenium庫和驅動

接下來我們把思路和程式碼說一下

1、首先匯入一下需要用到的模組

from selenium import webdriver
from bs4 import BeautifulSoup
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

2、因為這個頁面是動態的,我們的selenium檢測到瀏覽器框架之後就會返回原始碼,但是它不會去檢測這個頁面的動態載入部分是否加載出來,所以我們需要要求它去檢測一下

這兩個東西就是表示的是百度文庫中文庫是第幾頁,上圖表示的是百度文庫的第二頁的div元素,第三頁如下

這樣我就可以確定,這個肯定可以作為檢測條件

num = input('輸入總頁數:')
st = "pageNo-"
st_nums = st+str(num)    #先構建一下最後一頁的屬性值

3、使用selenium模擬瀏覽器,並開啟指定網址

browser = webdriver.Chrome("D:\python-senium\chromedriver.exe")#裡面傳的引數是你selenium驅動所在位置
browser.get('https://wenku.baidu.com/view/df34290a763231126edb11f9.html') #傳送請求

4、我們使用selenium中的顯示等待,初始化最長等待時間為10s。並等待我們要點選“繼續閱讀”出現,然後將瀏覽器頁面移動到這裡

wait = WebDriverWait(browser,10)
time.sleep(5)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#html-reader-go-more > div.continue-to-read > div.banner-more-btn > span')))#等待條件:找到文庫中“繼續閱讀”字樣,並等待其出現
page = browser.find_element_by_xpath("//*[@id='html-reader-go-more']/div[2]/div[1]/span") #找到頁面中“繼續閱讀”所在位置
#js = "document.getElementsByClassName('banner-more-btn').style.visibility='hidden'"
#browser.execute_script(js)  #這個js程式碼是我原來以為是“繼續閱讀”被一個空的div包裹所以不能點選,然後我嘗試把這個div掩蓋掉,結果js程式碼執行失敗。。。
browser.execute_script('arguments[0].scrollIntoView();', page) #拖動到可見的元素“繼續閱讀”去

5、等待“繼續閱讀”可以點選就點選它,然後等待文庫中最後一頁也加載出來就返回頁面原始碼

wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#html-reader-go-more > div.continue-to-read > div.banner-more-btn > span'))).click()
wait.until(EC.presence_of_element_located((By.ID,st_nums)))  #等待文庫中最後一頁也加載出來
html = browser.page_source

6、我們發現這些文字都被一個class屬性值為“ie-fix”所包裹,那我們就把它所包裹的p標籤都拿出來

its_p = soup.select(".ie-fix p")

然後對這個列表進行遍歷,並輸出其中的文字,並寫入檔案ab.txt中

soup = BeautifulSoup(html,"html.parser")  #使用python內建解析html庫
def get_context():
    try:
        its_p = soup.select(".ie-fix p")
        for it_p in its_p:
            print(it_p.text,end='')
            with open('ab.txt','a',encoding='utf-8') as f:
                f.write(it_p.text)
    except:
        print('出錯了')

get_context()  #呼叫函式
browser.close()   #關閉瀏覽器

全部程式碼:

from selenium import webdriver
from bs4 import BeautifulSoup
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

num = input('輸入總頁數:')
st = "pageNo-"
st_nums = st+str(num)
''''''
browser = webdriver.Chrome("D:\python-senium\chromedriver.exe")
browser.get('https://wenku.baidu.com/view/df34290a763231126edb11f9.html')
wait = WebDriverWait(browser,10)
time.sleep(5)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#html-reader-go-more > div.continue-to-read > div.banner-more-btn > span')))
page = browser.find_element_by_xpath("//*[@id='html-reader-go-more']/div[2]/div[1]/span")
#js = "document.getElementsByClassName('banner-more-btn').style.visibility='hidden'"
#browser.execute_script(js)
browser.execute_script('arguments[0].scrollIntoView();', page) #拖動到可見的元素去
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'#html-reader-go-more > div.continue-to-read > div.banner-more-btn > span'))).click()
wait.until(EC.presence_of_element_located((By.ID,st_nums)))
html = browser.page_source

soup = BeautifulSoup(html,"html.parser")
def get_context():
    try:
        its_p = soup.select(".ie-fix p")
        for it_p in its_p:
            print(it_p.text,end='')
            with open('ab.txt','a',encoding='utf-8') as f:
                f.write(it_p.text)
    except:
        print('出錯了')

get_context()
browser.close()

結果:

缺陷:

這個程式碼不會去爬取文庫中圖片資訊,所以要是爬取ppt等文庫還是不要用了(後面爬ppt的我會再寫一篇部落格)

提示:

也是後代碼會執行出錯,主要原因是time.sleep()的時間不夠長,可以根據自身情況調整,或者可以多執行幾次(如果有其他好的方法可以,希望大佬可以帶帶我^_^)