关于文章《爬取知网文献信息》中代码的一些优化

关于,文章,文献,信息,代码,一些,优化 · 浏览次数 : 127

小编点评

```python import WebDriverWait from selenium.webdriver.edge.options import EdgeOptions from selenium.webdriver.common.keys import Keys from open import open_page # 输入需要搜索的主题 theme = input("请输入你要搜索的期刊名称:") # 设置所需篇数 papers_need = int(input("请输入你要爬取篇数:")) # 设置不显示窗口 options.add_argument('--headless') # 创建一个浏览器驱动器 driver = webdriver.Edge(options=options) # 输入需要搜索的主题 input_box = driver.find_element_by_xpath("//*[@id='PageNext']//input") input_box.send_keys(theme) # 设置所需篇数 input_box = driver.find_element_by_xpath("//*[@id='PageNext']//input") input_box.send_keys(papers_need) # 获取页面 res_unm = int(open_page(driver, theme)) # 判断所需是否大于总篇数 papers_need = papers_need if (papers_need <= res_unm) else res_unm # Crawl crawl(driver, papers_need, theme) # 关闭浏览器 driver.close() # 打印爬取完毕! print("爬取完毕!") ``` **排版说明:** * 使用 `open()` 函数打开网页,并使用 `keys` 模块输入主题。 * 使用 `xpath` 模块定位输入框和按钮。 * 使用 `find_element_by_xpath` 函数找到输入框和按钮。 * 使用 `find_element_by_xpath` 函数找到页面加载完成的元素。 * 使用 `send_keys` 函数输入主题。 * 使用 `find_element_by_xpath` 函数找到所需篇数元素。 * 使用 `send_keys` 函数输入所需篇数。 * 使用 `find_element_by_xpath` 函数找到页面加载完成的元素。 * 使用 `send_keys` 函数输入所需篇数。 * 使用 `find_element_by_xpath` 函数找到页面加载完成的元素。 * 使用 `open()` 函数打开页面,并使用 `keys` 模块输入主题。

正文

哈喽大家好,我是咸鱼

 

之前写了一篇关于文献爬虫的文章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()
​
 

 

与关于文章《爬取知网文献信息》中代码的一些优化相似的内容:

关于文章《爬取知网文献信息》中代码的一些优化

哈喽大家好,我是咸鱼 之前写了一篇关于文献爬虫的文章Python爬虫实战(5) | 爬取知网文献信息 文章发布之后有很多小伙伴给出了一些反馈和指正,在认真看了小伙伴们的留言之后,咸鱼对代码进行了一些优化 优化的代码在文末,欢迎各位小伙伴给出意见和指正 问题 pycharm 设置 Edge 驱动器的环

python爬虫之根据期刊信息获取知网文献信息 pt.1

哈喽大家好,我是咸鱼 之前写过一篇获取知网文献信息的文章([关于《爬取知网文献信息》中代码的一些优化](http://mp.weixin.qq.com/s?__biz=MzkzNzI1MzE2Mw==&mid=2247485617&idx=1&sn=8c38163fc757784d3048e5043

Java爬虫-爬取疫苗批次信息

今年3月份开始,就接到通知, 根据《关于开展有关人群第二剂次脊髓灰质炎灭活疫苗补种工作的通知》国疾控卫免发〔2024〕1号文件要求,在2016年3月1日至2019年9月30日之间出生的儿童,凡无接种禁忌者,需补齐2剂次脊髓灰质炎灭活疫苗。由于我家一直是异地打针【在外漂打工,懂的都懂】,疫苗本上信息又

痞子衡嵌入式全部原创文章 - 汇总索引

职场经验与见闻感悟 痞子衡在嵌入式行业也摸打滚爬了不少年,有一些个人经验可以给大家参考。所谓他山之石可以攻玉,希望痞子衡的经验对大家的职场之路有所帮助。 职场经验篇(持续更新中...4/4) 职场上有效地向师傅请教问题的几点建议 关于做技术的工作态度方面的几点建议 工作多年的工程师且看这四条进阶之路

boltdb一瞥

boltdb 网上关于boltdb的文章有很多,特别是微信公众号上,例如: boltdb源码分析系列-事务-腾讯云开发者社区-腾讯云 (tencent.com) 这些文章都写的挺好,但不一定覆盖了我所关注的几个点,下面我把我关注的几个点就来下来。 node page bucket tx db的关系

Go语言性能剖析利器--pprof实战

作者:耿宗杰 前言 关于pprof的文章在网上已是汗牛充栋,却是千篇一律的命令介绍,鲜有真正实操的,本文将参考Go社区资料,结合自己的经验,实战Go程序的性能分析与优化过程。 优化思路 首先说一下性能优化的一般思路。系统性能的分析优化,一定是从大到小的步骤来进行的,即从业务架构的优化,到系统架构的优

【c#表达式树】最完善的表达式树Expression.Dynamic的玩法

引言 在我第一次写博客的时候,写的第一篇文章,就是关于表达式树的,链接:https://www.cnblogs.com/1996-Chinese-Chen/p/14987967.html,其中,当时一直没有研究Expression.Dynamic的使用方法(因为网上找不到资料),就了解到是程序运行时

聊聊GLM-4-9B开源模型的微调loss计算

概述 Github官方地址:GLM-4 网上已经有很多关于微调的文章,介绍各种方式下的使用,这里不会赘述。我个人比较关心的是微调时的loss计算逻辑,这点在很多的文章都不会有相关的描述,因为大多数人都是关心如何使用之类的应用层,而不是其具体的底层逻辑,当然咱也说不清太底层的计算。 可了解其它loss

games101-3 BRDF101

BRDF101 概述 本文基于知乎Maple对brdf的文章,在此基础又收集了一些其它来源的关于brdf的文章,希望能够完全理解记忆相关知识 关于Jakub Boksansky的文章,看的过程中又去搜集了很多其它文章来理解,发现已经超出了我目前的知识厚度,因此只会简单的翻译一下我能理解的部分,感兴趣

记一次 .NET 某医疗器械 程序崩溃分析

一:背景 1.讲故事 前段时间有位朋友在微信上找到我,说他的程序偶发性崩溃,让我帮忙看下怎么回事,上面给的压力比较大,对于这种偶发性崩溃,比较好的办法就是利用 AEDebug 在程序崩溃的时候自动抽一管血出来,看看崩溃点是什么,其实我的系列文章中,关于崩溃类的dump比较少,刚好补一篇上来,话不多说