哈嘍大家好,我是鹹魚 之前寫了一篇關於文獻爬蟲的文章Python爬蟲實戰(5) | 爬取知網文獻信息 文章發佈之後有很多小伙伴給出了一些反饋和指正,在認真看了小伙伴們的留言之後,鹹魚對代碼進行了一些優化 優化的代碼在文末,歡迎各位小伙伴給出意見和指正 問題 pycharm 設置 Edge 驅動器的環 ...
哈嘍大家好,我是鹹魚
之前寫了一篇關於文獻爬蟲的文章
文章發佈之後有很多小伙伴給出了一些反饋和指正,在認真看了小伙伴們的留言之後,鹹魚對代碼進行了一些優化
優化的代碼在文末,歡迎各位小伙伴給出意見和指正
問題
-
pycharm 設置 Edge 驅動器的環境報錯
“module 'selenium.webdriver' has no attribute 'EdgeOptions”
如果瀏覽器驅動已經下載,而放在了合適的位置(比如添加到環境變數里,或者放在了 python.exe 同級目錄中)
那就可能是因為你使用的是較老的版本,Edge的選項已經被更新了。 建議更新 selenium 包以獲得最佳的Edge選項支持
可以通過以下命令更新 selenium,建議更新到 4.6 以上版本
pip install -U selenium
因為 selenium 4.6 版本之後內置了一個組件:Selenium Manager
根據官網介紹,這個 Selenium Manager 可以幫助你獲得一個運行 Selenium 的開箱即用的環境
如果在 PATH 中沒有找到 Chrome、Firefox 和 Edge 的驅動,Selenium Manager的 Beta 1版將為它們配置。不需要額外的配置
這就意味著自己不需要再去下載安裝瀏覽器驅動
中文文檔鏈接:
https://www.selenium.dev/zh-cn/documentation/webdriver/getting_started/install_drivers/
-
只能爬取20倍數的文獻篇數
有位粉絲發現每次爬取都是爬取 20 倍數的文獻篇數(20、40、60)。假設要爬取 21 篇,但是卻爬到了 40 篇
排查的時候發現是代碼中的邏輯有一些 bug ,已經優化
-
獲取不到網頁的 xpath 元素
第一種可能是網頁中的 xpath 元素並不是一成不變的,要參考自己的瀏覽器上的 Xpath。在我這可能是div[3],在你那可能就不是這個了,所以說需要自己先定位一遍
第二種可能是網頁載入太慢導致爬蟲爬取不到,這種情況的話可以增加等待超時時間
-
關於網頁載入太慢導致程式爬取不到元素報超時異常或者元素不存在異常
我的代碼中用的都是顯示等待 + 強制等待結合的方式。如果還是不行,小伙伴們可以自行設置超時時間
優化後代碼
下麵給出優化後的源碼
import time from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from urllib.parse import urljoin def open_page(driver, theme): # 打開頁面 driver.get("https://www.cnki.net") # 傳入關鍵字 WebDriverWait(driver, 100).until( EC.presence_of_element_located((By.XPATH, '''//*[@id="txt_SearchText"]'''))).send_keys(theme) # 點擊搜索 WebDriverWait(driver, 100).until( EC.presence_of_element_located((By.XPATH, "/html/body/div[2]/div[2]/div/div[1]/input[2]"))).click() time.sleep(3) # 點擊切換中文文獻 WebDriverWait(driver, 100).until( EC.presence_of_element_located((By.XPATH, "/html/body/div[3]/div[1]/div/div/div/a[1]"))).click() time.sleep(3) # 獲取總文獻數和頁數 res_unm = WebDriverWait(driver, 100).until(EC.presence_of_element_located( (By.XPATH, "/html/body/div[3]/div[2]/div[2]/div[2]/form/div/div[1]/div[1]/span[1]/em"))).text # 去除千分位里的逗號 res_unm = int(res_unm.replace(",", '')) page_unm = int(res_unm / 20) + 1 print(f"共找到 {res_unm} 條結果, {page_unm} 頁。") return res_unm def crawl(driver, papers_need, theme): # 賦值序號, 控制爬取的文章數量 count = 1 # 當爬取數量小於需求時,迴圈網頁頁碼 while count <= papers_need: # 等待載入完全,休眠3S time.sleep(3) title_list = WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located((By.CLASS_NAME, "fz14"))) # 迴圈網頁一頁中的條目 for i in range(len(title_list)): try: if (count % 20) != 0: term = count % 20 # 本頁的第幾個條目 else: term = 20 title_xpath = f"/html/body/div[3]/div[2]/div[2]/div[2]/form/div/table/tbody/tr[{term}]/td[2]" author_xpath = f"/html/body/div[3]/div[2]/div[2]/div[2]/form/div/table/tbody/tr[{term}]/td[3]" source_xpath = f"/html/body/div[3]/div[2]/div[2]/div[2]/form/div/table/tbody/tr[{term}]/td[4]" date_xpath = f"/html/body/div[3]/div[2]/div[2]/div[2]/form/div/table/tbody/tr[{term}]/td[5]" database_xpath = f"/html/body/div[3]/div[2]/div[2]/div[2]/form/div/table/tbody/tr[{term}]/td[6]" title = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, title_xpath))).text authors = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, author_xpath))).text source = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, source_xpath))).text date = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, date_xpath))).text database = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, database_xpath))).text # 點擊條目 title_list[i].click() # 獲取driver的句柄 n = driver.window_handles # driver切換至最新生產的頁面 driver.switch_to.window(n[-1]) time.sleep(3) # 開始獲取頁面信息 title = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH ,"/html/body/div[2]/div[1]/div[3]/div/div/div[3]/div/h1"))).text authors = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH ,"/html/body/div[2]/div[1]/div[3]/div/div/div[3]/div/h3[1]"))).text institute = WebDriverWait(driver, 10).until(EC.presence_of_element_located( (By.XPATH, "/html/body/div[2]/div[1]/div[3]/div/div/div[3]/div/h3[2]"))).text abstract = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CLASS_NAME, "abstract-text"))).text try: keywords = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CLASS_NAME, "keywords"))).text[:-1] cssci = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, "/html/body/div[2]/div[1]/div[3]/div/div/div[1]/div[1]/a[2]"))).text except: keywords = '無' cssci = 'NULL' url = driver.current_url res = f"{count}\t{title}\t{authors}\t{cssci}\t{institute}\t{date}\t{source}\t{database}\t{keywords}\t{abstract}\t{url}".replace( "\n", "") + "\n" print(res) '''寫入文件,有需要的小伙伴可以去掉註釋''' # with open(f'CNKI_{theme}.tsv', 'a', encoding='gbk') as f: # f.write(res) except: print(f" 第{count} 條爬取失敗\n") # 跳過本條,接著下一個 continue finally: # 如果有多個視窗,關閉第二個視窗, 切換回主頁 n2 = driver.window_handles if len(n2) > 1: driver.close() driver.switch_to.window(n2[0]) # 爬完一篇計數加 1 count += 1 if count > papers_need: break WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//a[@id='PageNext']"))).click() if __name__ == "__main__": print("開始爬取!") # get直接返回,不再等待界面載入完成 desired_capabilities = DesiredCapabilities.CHROME desired_capabilities["pageLoadStrategy"] = "none" # 設置驅動器的環境 options = webdriver.EdgeOptions() # 設置chrome不載入圖片,提高速度 options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2}) # 設置不顯示視窗 options.add_argument('--headless') # 創建一個瀏覽器驅動器 driver = webdriver.Edge(options=options) # 輸入需要搜索的主題 # theme = input("請輸入你要搜索的期刊名稱:") theme = "python" # 設置所需篇數 # papers_need = int(input("請輸入你要爬取篇數:")) papers_need = 100 res_unm = int(open_page(driver, theme)) # 判斷所需是否大於總篇數 papers_need = papers_need if (papers_need <= res_unm) else res_unm crawl(driver, papers_need, theme) print("爬取完畢!") # 關閉瀏覽器 driver.close()