selenium 知網爬蟲之根據【關鍵詞】獲取文獻信息

来源:https://www.cnblogs.com/edisonfish/archive/2023/10/28/17793652.html
-Advertisement-
Play Games

哈嘍大家好,我是鹹魚 之前鹹魚寫過幾篇關於知網爬蟲的文章,後臺反響都很不錯。雖然但是,鹹魚還是忍不住想訴苦一下 有些小伙伴文章甚至代碼看都沒看完,就問我 ”為什麼只能爬這麼多條文獻信息?“(看過代碼的會發現我代碼裡面定義了 papers_need 變數來設置爬取篇數),”為什麼爬其他文獻不行?我想爬 ...


哈嘍大家好,我是鹹魚

之前鹹魚寫過幾篇關於知網爬蟲的文章,後臺反響都很不錯。雖然但是,鹹魚還是忍不住想訴苦一下

有些小伙伴文章甚至代碼看都沒看完,就問我 ”為什麼只能爬這麼多條文獻信息?“(看過代碼的會發現我代碼裡面定義了 papers_need 變數來設置爬取篇數),”為什麼爬其他文獻不行?我想爬 XXX 文獻“(因為代碼裡面寫的是通過【知網高級搜索中的文獻來源】來搜索文章),或者是有些小伙伴直接把代碼報錯貼給我,問我咋回事

我覺得在網上看到別人的代碼,不要一昧地拿來主義,複製粘貼就行了,你要結合你自己的本地環境對代碼做適當地修改。比如定位 Xpath 元素路徑,不通電腦或者說不同瀏覽器同一元素的 Xpath 路徑有可能不是一樣的,這個路徑在我本地運行沒問題,到了你那裡就報錯

當看別人的代碼時,最好先搞清楚:

  1. 別人是怎麼想的
  2. 別人為什麼要這麼寫
  3. 這麼寫的邏輯是什麼?

以我這幾篇知網爬蟲文章舉例:

  1. 為什麼要用 selenium 來爬取?
  2. 如何分析網頁?如何定位元素?(Xpath、CSS 選擇器等等)
  3. 如何通過 selenium 來模擬人為操作瀏覽器(滑鼠移動、點擊、滑動視窗等等)

言歸正傳,鹹魚昨天收到一位粉絲私信說能不能根據【關鍵詞】來搜索文獻
image
今天這篇文章著重講如何分析網頁結構然後使用 selenium 根據知網的關鍵詞來搜索文獻。至於對搜索到的文獻的爬取,本文不過多介紹,因為以前的文章已經寫過了

需求分析

我們先來看下如果要通過關鍵詞搜索文獻,該怎麼操作?

知網:中國知網 (cnki.net)

首先我們登錄網站,點擊【高級搜索】(也可以直接點擊搜索框中的【主題】下拉選擇)
image
然後我們點擊【主題】——>選擇【關鍵詞】
image
image
輸入要搜索的關鍵詞(例如:數字普惠金融)然後點擊【檢索】
image

網頁分析&元素定位

結合前面的需求分析,我們就可以對網頁進行分析並定位出對應的元素

首先是【高級搜索】,高級搜索有一個鏈接:高級檢索-中國知網 (cnki.net),這樣就能省掉一個步驟了

然後我們需要點擊 【主題】,才會出現下拉框。在分析網頁的時候我發現當出現下拉框時,標簽 <div class="sort-list" style="display: none;">" 中的 style 屬性由 "display: none;" 變成 "display: block;"
image
下拉框出現之後,我們需要定位到 【關鍵詞】 這個標簽

# 關鍵詞 Xpath 路徑或 CSS 選擇器
//*[@id="gradetxt"]/dd[1]/div[2]/div[1]/div[2]/ul/li[3]

li[data-val="KY"]

image
接著找到【搜索框】的 Xpath 路徑。這裡是一個 input 元素,用於接收來自用戶的數據

# 輸入框
//*[@id="gradetxt"]/dd[1]/div[2]/input

image

往輸入框傳入數據之後,我們需要點擊下麵的【檢索】按鈕

# 檢索
/html/body/div[2]/div/div[2]/div/div[1]/div[1]/div[2]/div[2]/input

image
點擊搜索之後我們把【文獻條數】爬取下來

# 文獻條數
/html/body/div[3]/div[2]/div[2]/div[2]/form/div/div[1]/div[1]/span[1]/em

image

代碼實現

selenium 是一個自動化測試工具,可以用來進行 web 自動化測試。其本質是通過驅動瀏覽器,完全模擬瀏覽器的操作(比如跳轉、輸入、點擊、下拉等)來實現網頁渲染之後的結果,可支持多種瀏覽器

爬蟲中用到 selenium 主要是為瞭解決 requests 無法直接執行 JavaScript 代碼等問題

導入相關庫

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 selenium.webdriver.common.action_chains import ActionChains

創建瀏覽器對象

這裡我用的是 Edge 瀏覽器

def webserver():
    # get直接返回,不再等待界面載入完成
    desired_capabilities = DesiredCapabilities.EDGE
    desired_capabilities["pageLoadStrategy"] = "none"

    # 設置微軟碟機動器的環境
    options = webdriver.EdgeOptions()
    
    # 設置瀏覽器不載入圖片,提高載入速度
    options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})

    # 創建一個微軟碟機動器
    driver = webdriver.Edge(options=options)
    return driver

爬取網頁

其實邏輯並不難,就是先定位到各個元素然後用 selenium 來模擬我們人為點擊瀏覽器的操作就行了

首先打開頁面,等待個一兩秒讓網頁完全載入

    driver.get("https://kns.cnki.net/kns8/AdvSearch")
    time.sleep(2)

然後然下拉框顯示出來,前面我們提到:標簽 <div class="sort-list" style="display: none;">" 中的 style 屬性由 "display: none;" 變成 "display: block;" 時,就會出現下拉框

這裡我們通過執行 js 腳本來修改裡面的 style 屬性

    # 修改屬性,使下拉框顯示
    opt = driver.find_element(By.CSS_SELECTOR, 'div.sort-list')  # 定位下拉框
    # 執行 js 腳本進行屬性的修改; arguments[0]代表第一個屬性
    driver.execute_script("arguments[0].setAttribute('style', 'display: block;')", opt)  

下拉框顯示出來之後我們需要點擊【關鍵詞】,這樣才會切換到關鍵詞搜索

這裡需要註意的是,當我在測試的時候發現下拉框載入是有問題的,這時候代碼會報錯說Element <li data-val="KY">...</li> is not clickable at point (189, 249)

就會使得程式點擊不了【關鍵詞】
image
而且我還發現如果載入不完全的話,需要滑鼠移動到下拉框那裡,讓下拉框完全載入。所以這裡我使用了 selenium 中的 ActionChains 來模擬滑鼠的操作

用 selenium 做自動化,有時候會遇到需要模擬滑鼠操作才能進行的情況,比如單擊、雙擊、點擊滑鼠右鍵、拖拽等等

selenium 給我們提供了一個類來處理這類事件——ActionChains

還有一點需要註意的是:如果滑鼠只是移到【關鍵詞】,下拉框其實還是不能正確載入出來,最好是移動到下拉框的最底部或者關鍵詞後面的元素,這裡我移動到【通訊作者】

# 【通訊作者】定位
/html/body/div[2]/div/div[2]/div/div[2]/div[1]/div[1]/div[2]/ul/li[8]

li[data-val="RP"]

image

下拉框載入完成之後,定位到【關鍵詞】再點擊

    # 滑鼠移動到下拉框
    ActionChains(driver).move_to_element(driver.find_element(By.CSS_SELECTOR, 'li[data-val="RP"]')).perform()

    # 找到[關鍵詞]選項並點擊
    WebDriverWait(driver, 100).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, 'li[data-val="KY"]'))).click()

定位出搜索框,傳入我們要搜索的關鍵詞

    # 傳入關鍵字
    WebDriverWait(driver, 100).until(
        EC.presence_of_element_located((By.XPATH, '''//*[@id="gradetxt"]/dd[1]/div[2]/input'''))
    ).send_keys(keyword)

    # 點擊搜索
    WebDriverWait(driver, 100).until(
        EC.presence_of_element_located((By.XPATH, "/html/body/div[2]/div/div[2]/div/div[1]/div[1]/div[2]/div[2]/input"))
    ).click()

搜索結果出來之後定位【文獻條數】,獲取對應的條數(text 標簽)

    # 獲取總文獻數和頁數
    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

完整代碼如下:

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 selenium.webdriver.common.action_chains import ActionChains


def webserver():
    # get直接返回,不再等待界面載入完成
    desired_capabilities = DesiredCapabilities.EDGE
    desired_capabilities["pageLoadStrategy"] = "none"

    # 設置微軟碟機動器的環境
    options = webdriver.EdgeOptions()
    # 設置瀏覽器不載入圖片,提高速度
    options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})

    # 創建一個微軟碟機動器
    driver = webdriver.Edge(options=options)

    return driver


def open_page(driver, keyword):
    # 打開頁面,等待兩秒
    driver.get("https://kns.cnki.net/kns8/AdvSearch")
    time.sleep(2)

    # 修改屬性,使下拉框顯示
    opt = driver.find_element(By.CSS_SELECTOR, 'div.sort-list')  # 定位元素
    driver.execute_script("arguments[0].setAttribute('style', 'display: block;')", opt)  # 執行 js 腳本進行屬性的修改;arguments[0]代表第一個屬性

    # 滑鼠移動到下拉框中的[通訊作者]
    ActionChains(driver).move_to_element(driver.find_element(By.CSS_SELECTOR, 'li[data-val="RP"]')).perform()

    # 找到[關鍵詞]選項並點擊
    WebDriverWait(driver, 100).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, 'li[data-val="KY"]'))).click()

    # 傳入關鍵字
    WebDriverWait(driver, 100).until(
        EC.presence_of_element_located((By.XPATH, '''//*[@id="gradetxt"]/dd[1]/div[2]/input'''))
    ).send_keys(keyword)

    # 點擊搜索
    WebDriverWait(driver, 100).until(
        EC.presence_of_element_located((By.XPATH, "/html/body/div[2]/div/div[2]/div/div[1]/div[1]/div[2]/div[2]/input"))
    ).click()

    # 點擊切換中文文獻
    WebDriverWait(driver, 100).until(
        EC.presence_of_element_located((By.XPATH, "/html/body/div[3]/div[1]/div/div/div/a[1]"))
    ).click()

    # 獲取總文獻數和頁數
    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} 頁。")


if __name__ == '__main__':
    keyword = "數字普惠金融"
    driver = webserver()
    open_page(driver, keyword)

結果如下:
image


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

-Advertisement-
Play Games
更多相關文章
  • 可移動嵌入式設備是數據客戶端的一種表現形式。軟體的代碼編寫之後是運行在伺服器之上, 伺服器的數據為客戶端提供服務的模式為伺服器客戶端模式,server2client 架構。伺服器可以是大型的機器,也可以是小型機,主要看數據處理量和用戶量的大小。一臺電腦其實就是一臺簡單的伺服器,電腦的存在是使用中 ...
  • 一些研發工程師在Springboot註意點1. 正確設計代碼目錄結構雖然您有很大的自由度,但有一些基本規則值得遵循來設計您的源代碼結構。避免使用預設包。確保所有內容(包括入口點)都在命名良好的包中,這樣您就可以避免與組裝和組件掃描相關的意外情況;將 Application.java(應用程式的入口類 ...
  • 變數只在創建它的區域內可用。這被稱為作用域。 局部作用域 在函數內部創建的變數屬於該函數的局部作用域,並且只能在該函數內部使用。 示例:在函數內部創建的變數在該函數內部可用: def myfunc(): x = 300 print(x) myfunc() 函數內部的函數 如上面的示例所解釋的那樣,變 ...
  • 一.數組 數組的定義:相同類型的數據集合 go語言中數組的索引從0開始 沒有賦值的數值型數組,預設值為0 數組一旦被創建,它的大小就是不可改變的 (1)聲明數組與列印 var 變數名 [大小]變數類型 //數組的聲明 var nums [4]int //數組的賦值 nums[0] = 1 nums[ ...
  • 對於日常開發者來講很少會使用到本章節的內容,但是對框架作者等是必備知識,同時也是高頻的面試常見問題。 1.線程安全 線程安全是多線程或多進程編程中的一個概念,在擁有共用數據的多條線程並行執行的程式中,線程安全的代碼會通過同步機制保證各個線程都可以正常且正確的執行,不會出現數據污染等意外情況。 線程安 ...
  • 在寫代碼的時候,免不了要使用變數。但程式中的一個變數並不一定是在哪裡都可以被使用,根據情況不同,會有不同的“有效範圍”。 看這樣一段代碼: def func(x): print ('X in the beginning of func(x): ', x) x = 2 print ('X in the ...
  • 用go封裝一下臨時token 本篇為用go設計開發一個自己的輕量級登錄庫/框架吧 的臨時token篇,會講講臨時token的實現,給庫/框架增加新的功能。 Github:https://github.com/weloe/token-go 臨時token也算是比較常見的業務,例如登錄驗證碼信息,邀請鏈 ...
  • 操作系統 :CentOS 7.6_x64 FreeSWITCH版本 :1.10.9 之前寫過FreeSWITCH添加自定義endpoint的文章,今天整理下api及app開發的筆記。歷史文章可參考如下鏈接: FreeSWITCH添加自定義endpointFreeSWITCH添加自定義endpoint ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...