關於文章《爬取知網文獻信息》中代碼的一些優化

来源:https://www.cnblogs.com/edisonfish/archive/2023/04/27/17357929.html
-Advertisement-
Play Games

哈嘍大家好,我是鹹魚 之前寫了一篇關於文獻爬蟲的文章Python爬蟲實戰(5) | 爬取知網文獻信息 文章發佈之後有很多小伙伴給出了一些反饋和指正,在認真看了小伙伴們的留言之後,鹹魚對代碼進行了一些優化 優化的代碼在文末,歡迎各位小伙伴給出意見和指正 問題 pycharm 設置 Edge 驅動器的環 ...


哈嘍大家好,我是鹹魚

 

之前寫了一篇關於文獻爬蟲的文章Python爬蟲實戰(5) | 爬取知網文獻信息

 

文章發佈之後有很多小伙伴給出了一些反饋和指正,在認真看了小伙伴們的留言之後,鹹魚對代碼進行了一些優化

 

優化的代碼在文末,歡迎各位小伙伴給出意見和指正

 

問題

  • 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 += 1if 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()
​
 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • MySQL業務設計 作者: 博學谷狂野架構師 GitHub:GitHub地址 (有我精心準備的130本電子書PDF) 只分享乾貨、不吹水,讓我們一起加油!😄 邏輯設計 範式設計 範式概述 **第一範式:**當關係模式R的所有屬性都不能在分解為更基本的數據單位時,稱R是滿足第一範式的,簡記為1NF。 ...
  • 摘要:節點(Node)是通過 ROS 圖進行通信的可執行進程。 本文分享自華為雲社區《編寫一個簡單的發佈者和訂閱者》,作者: MAVER1CK 。 @[toc] 參考官方文檔:Writing a simple publisher and subscriber (C++) 背景 節點(Node)是通過 ...
  • 1. 簡介 在go中,slice是一種動態數組類型,其底層實現中使用了數組。slice有以下特點: *slice本身並不是數組,它只是一個引用類型,包含了一個指向底層數組的指針,以及長度和容量。 *slice的長度可以動態擴展或縮減,通過append和copy操作可以增加或刪除slice中的元素。 ...
  • 三種初始化數據域的方法: 在構造器中設置值 在聲明中賦值 初始化塊(initialization block) 初始化塊 在一個類的聲明中,可以包含多個代碼塊。只要構造類的對象,這些塊就會被執行。 class Employee { private static int nextId; private ...
  • 現代的垃圾回收器為了低停頓的目標可謂將“併發”二字玩到極致,Shenandoah在G1基礎上做了非常多的優化來使回收階段並行,而ZGC直接採用了染色指針、NUMA等黑科技,目的都是為了讓Java開發者可以更多的將精力放在如何使用對象讓程式更好的運行,剩下的一切交給GC,我們所做的只需享受現代化GC技... ...
  • 教程簡介 Word 2010入門教程 - 從簡單的步驟入門Microsoft Office 2010,從基本到高級概念,包括探索視窗,後臺視圖,輸入文本,移動,打開,關閉文檔,上下文幫助,插入,選擇,刪除,移動測試,複製和粘貼,查找和替換,拼寫檢查,特殊符號,撤消更改,設置文本字體,文本修飾,更改測 ...
  • 教程簡介 WPF(Windows Presentation Foundation)是微軟推出的基於Windows 的用戶界面框架,屬於.NET Framework的一部分。它提供了統一的編程模型、語言和框架,真正做到了分離界面設計人員與開發人員的工作;同時它提供了全新的多媒體交互用戶圖形界面。 WP ...
  • SpringBoot 集成 SpringSecurity + MySQL + JWT 附源碼,廢話不多直接盤 SpringBoot已經為用戶採用預設配置,只需要引入pom依賴就能快速啟動Spring Security。 目的:驗證請求用戶的身份,提供安全訪問 優勢:基於Spring,配置方便,減少大 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...