网站建设定制开发Python爬虫,批量获取知网文献信息

一、前言

网站建设定制开发最近临近毕业,网站建设定制开发写毕业论文需要从知网网站建设定制开发查找大量的文献。网站建设定制开发但去知网一条一条进去网站建设定制开发看摘要又略显麻烦和浪费时间。于是,网站建设定制开发反手写一个,网站建设定制开发批量获取基本信息,岂不美哉?

网站建设定制开发在开始这个项目之前,网站建设定制开发我抱着不重复造轮子的心态,网站建设定制开发寻思着去先找找。网站建设定制开发结果发现基本上都是几网站建设定制开发年前的项目,网站建设定制开发现在早已不能使用。最后证实了,靠别人不如靠自己,撸起袖子就开干!

1. 爬虫基础

网络爬虫就是模拟浏览器发送网络请求,接收请求响应,一种按照一定的规则,自动地抓取互联网信息的程序。
目前爬虫主要分为以 requests 库为代表的模拟请求类爬虫和以 selenium 为代表的模拟浏览器用户行为的爬虫两类。:

  • Requests 是用Python语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测试需求。Requests 的哲学是以 PEP 20 的习语为中心开发的,所以它比 urllib 更加 Pythoner。

  • Selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE,Mozilla Firefox,Safari,Google Chrome,Opera等。

中国知网作为国内最知名的文献数据库之一,有着复杂的反爬虫机制,包括:动态JS、iframe、验证码等等。直接模拟请求难度较大,且容易被封IP地址,所以本文主要介绍如何使用Selenium来爬取知网。

2. Selenium基本用法

  • 声明浏览器对象

Selenium支持非常多的浏览器,如Chrome、Firefox、Edge等,我们只要首先下载好相应浏览器的webdriver到python主目录中,或者加入环境变量即可。

不同浏览器的初始化:

  1. from selenium import webdriver
  2. browser = webdriver.Chrome()
  3. browser = webdriver.Firefox()
  4. browser = webdriver.Edge()
  5. browser = webdriver.Safari()
  • 访问页面

我们可以用get()方法来请求一个网页,传入参数链接URL

browser.get('https://www.bing.com')
  • 查找元素

  1. find_element_by_id()
  2. find_element_by_name()
  3. find_element_by_class_name()
  4. find_element_by_tag_name()
  5. find_element_by_link_text()
  6. find_element_by_partial_link_text()
  7. find_element_by_xpath()
  8. find_element_by_css_selector()

在element变成elements就是找所有满足的条件,返回数组。
另外,我经常使用的查找元素方法为selenium中selenium.webdriver.common.by的By, 联合隐士等待EC
用法如下:

  1. # 单个元素
  2. WebDriverWait( driver, 10 ).until( EC.presence_of_element_located((By.XPATH ,"") ) )
  3. # 多个元素
  4. WebDriverWait( driver, 10 ).until( EC.presence_of_all_elements_located( (By.CLASS_NAME ,"fz14") ) )
  5. # 元素类型有:
  6. CLASS_NAME = 'class name'
  7. CSS_SELECTOR = 'css selector'
  8. ID = 'id'
  9. LINK_TEXT = 'link text'
  10. NAME = 'name'
  11. PARTIAL_LINK_TEXT = 'partial link text'
  12. TAG_NAME = 'tag name'
  13. XPATH = 'xpath'
  • 常用方法

在找到相应元素位置后,我们常用的交互动作包括:点击、输入、清楚、获取属性、获取文本等

  1. element = find_element_by_id(''id)
  2. element.send_keys('Hello') # 传入Hello
  3. element.clear() # 清除输入框
  4. element.click() # 点击元素
  5. element.text # 获取元素文本信息
  6. element.get_attribute('href') # 获取元素属性

还有大量的方法这里没有提及,不过有了以上基本知识,我们就可以开始项目了!

二、知网爬虫实战

1. 知网页面元素分析

知网首页中,我们仅需要先在输入框中键入主题词,然后点击搜索图标,即可跳转到结果页面。

 

我们通过浏览器的检查页面,得到输入框和搜索图标的XPATH分别为:

  1. input_xpath = '/html[1]/body[1]/div[1]/div[2]/div[1]/div[1]/input[1]'
  2. button_xpath = '/html[1]/body[1]/div[1]/div[2]/div[1]/div[1]/input[2]'

只需要在输入框键入我们要搜索的主题,然后操作搜索按钮即可转到结果页。以搜索Python为例,结果页如下所示,共找到15,925条,300页。每页中包含20个条目,每个条目包含题目、作者、来源等信息。

 

通过对当前页面分析,发现每个条目对应的的xpath的规律。

/html[1]/body[1]/div[5]/div[2]/div[2]/div[2]/form[1]/div[1]/table[1]/tbody[1]/tr[1]/td[2]

即倒数第二个标签数字代表本页的第几个条目,最后一个标签 2 - 6 分别代表题目、作者、来源、发表时间和数据库。

在当前页面无法或者文献的摘要信息,下载链接等等,需要进一步点击进入相关文献条目。

进入详情页面后,我们根据class name:abstract-text 能够很容易定位到摘要的文本,class name: btn-dlcaj 定位到下载链接,其他元素同理。


完成以上知网页面的分析后,我们就可以根据需求开始写代码了!

 

2. 代码示例

  • 引用所需要的库

  1. import time
  2. from selenium import webdriver
  3. from selenium.webdriver.support.ui import WebDriverWait
  4. from selenium.webdriver.support import expected_conditions as EC
  5. from selenium.webdriver.common.by import By
  6. from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
  7. from urllib.parse import urljoin
  • 创建浏览器对象

这里我们创建一个Chrome浏览器的窗口,并设置相关参数:

  1. #get直接返回,不再等待界面加载完成
  2. desired_capabilities = DesiredCapabilities.CHROME
  3. desired_capabilities["pageLoadStrategy"] = "none"
  4. # 设置谷歌驱动器的环境
  5. options = webdriver.ChromeOptions()
  6. # 设置chrome不加载图片,提高速度
  7. options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})
  8. # 设置不显示窗口
  9. #options.add_argument('--headless')
  10. # 创建一个谷歌驱动器
  11. driver = webdriver.Chrome(options=options)
  12. # 设置搜索主题
  13. theme = "Python"
  14. # 设置所需篇数
  15. papers_need = 100
  • 打开页面并搜索关键词

  1. # 打开页面
  2. driver.get("https://www.cnki.net")
  3. # 传入关键字
  4. WebDriverWait( driver, 100 ).until( EC.presence_of_element_located( (By.XPATH ,'''//*[@id="txt_SearchText"]''') ) ).send_keys(theme)
  5. # 点击搜索
  6. WebDriverWait( driver, 100 ).until( EC.presence_of_element_located( (By.XPATH ,"/html/body/div[1]/div[2]/div/div[1]/input[2]") ) ).click()
  7. time.sleep(3)
  8. # 点击切换中文文献
  9. WebDriverWait( driver, 100 ).until( EC.presence_of_element_located( (By.XPATH ,"/html/body/div[5]/div[1]/div/div/div/a[1]") ) ).click()
  10. time.sleep(1)
  11. # 获取总文献数和页数
  12. res_unm = WebDriverWait( driver, 100 ).until( EC.presence_of_element_located( (By.XPATH ,"/html/body/div[5]/div[2]/div[2]/div[2]/form/div/div[1]/div[1]/span[1]/em") ) ).text
  13. # 去除千分位里的逗号
  14. res_unm = int(res_unm.replace(",",''))
  15. page_unm = int(res_unm/20) + 1
  16. print(f"共找到 {res_unm} 条结果, {page_unm} 页。")
  • 解析结果页

  1. # 赋值序号, 控制爬取的文章数量
  2. count = 1
  3. # 当,爬取数量小于需求时,循环网页页码
  4. while count <= papers_need:
  5. # 等待加载完全,休眠3S
  6. time.sleep(3)
  7. title_list = WebDriverWait( driver, 10 ).until( EC.presence_of_all_elements_located( (By.CLASS_NAME ,"fz14") ) )
  8. # 循环网页一页中的条目
  9. for i in range(len(title_list)):
  10. try:
  11. term = count%20 # 本页的第几个条目
  12. title_xpath = f"/html[1]/body[1]/div[5]/div[2]/div[2]/div[2]/form[1]/div[1]/table[1]/tbody[1]/tr[{term}]/td[2]"
  13. author_xpath = f"/html[1]/body[1]/div[5]/div[2]/div[2]/div[2]/form[1]/div[1]/table[1]/tbody[1]/tr[{term}]/td[3]"
  14. source_xpath = f"/html[1]/body[1]/div[5]/div[2]/div[2]/div[2]/form[1]/div[1]/table[1]/tbody[1]/tr[{term}]/td[4]"
  15. date_xpath = f"/html[1]/body[1]/div[5]/div[2]/div[2]/div[2]/form[1]/div[1]/table[1]/tbody[1]/tr[{term}]/td[5]"
  16. database_xpath = f"/html[1]/body[1]/div[5]/div[2]/div[2]/div[2]/form[1]/div[1]/table[1]/tbody[1]/tr[{term}]/td[6]"
  17. title = WebDriverWait( driver, 10 ).until( EC.presence_of_element_located((By.XPATH ,title_xpath) ) ).text
  18. authors = WebDriverWait( driver, 10 ).until( EC.presence_of_element_located((By.XPATH ,author_xpath) ) ).text
  19. source = WebDriverWait( driver, 10 ).until( EC.presence_of_element_located((By.XPATH ,source_xpath) ) ).text
  20. date = WebDriverWait( driver, 10 ).until( EC.presence_of_element_located((By.XPATH ,date_xpath) ) ).text
  21. database = WebDriverWait( driver, 10 ).until( EC.presence_of_element_located((By.XPATH ,database_xpath) ) ).text
  22. # 点击条目
  23. title_list[i].click()
  24. # 获取driver的句柄
  25. n = driver.window_handles
  26. # driver切换至最新生产的页面
  27. driver.switch_to_window(n[-1])
  28. # 开始获取页面信息
  29. # 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
  30. # 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
  31. institute = WebDriverWait( driver, 10 ).until( EC.presence_of_element_located((By.XPATH ,"/html[1]/body[1]/div[2]/div[1]/div[3]/div[1]/div[1]/div[3]/div[1]/h3[2]") ) ).text
  32. abstract = WebDriverWait( driver, 10 ).until( EC.presence_of_element_located((By.CLASS_NAME ,"abstract-text") ) ).text
  33. try:
  34. keywords = WebDriverWait( driver, 10 ).until( EC.presence_of_element_located((By.CLASS_NAME ,"keywords") ) ).text[:-1]
  35. except:
  36. keywords = '无'
  37. url = driver.current_url
  38. # 获取下载链接
  39. # link = WebDriverWait( driver, 10 ).until( EC.presence_of_all_elements_located((By.CLASS_NAME ,"btn-dlcaj") ) )[0].get_attribute('href')
  40. # link = urljoin(driver.current_url, link)
  41. # 写入文件
  42. res = f"{count}\t{title}\t{authors}\t{institute}\t{date}\t{source}\t{database}\t{keywords}\t{abstract}\t{url}".replace("\","")+"\"
  43. print(res)
  44. with open('CNKI_res.tsv', 'a', encoding='gbk') as f:
  45. f.write(res)
  46. except:
  47. print(f" 第{count} 条爬取失败\")
  48. # 跳过本条,接着下一个
  49. continue
  50. finally:
  51. # 如果有多个窗口,关闭第二个窗口, 切换回主页
  52. n2 = driver.window_handles
  53. if len(n2) > 1:
  54. driver.close()
  55. driver.switch_to_window(n2[0])
  56. # 计数,判断需求是否足够
  57. count += 1
  58. if count == papers_need:break
  59. # 切换到下一页
  60. WebDriverWait( driver, 10 ).until( EC.presence_of_element_located( (By.XPATH ,"//a[@id='PageNext']") ) ).click()
  61. # 关闭浏览器
  62. driver.close()

至此,所有功能都已实现,代码中写了详细的注释。需要获得完整代码的可以直达我的Github下载,CNKI_Spider.py(https://github.com/byemaxx/BioTools)。

结果展示

结果是一个以制表符分隔的表格文件,其中包含了论文的基本信息,包括:题目、作者、来源、摘要、链接等

三、遇到的一些坑

1. 网页加载太慢导致元素查找出错

有时候我们并不需要网页完全,我们想要的信息已经加载出来,于是加上以下设置:

  1. #get直接返回,不再等待界面加载完成
  2. desired_capabilities = DesiredCapabilities.CHROME
  3. desired_capabilities["pageLoadStrategy"] = "none"

另一方面,在适当的地方加上 time.sleep(3) 延时几秒,既可以等待页面加载,也可以防止爬取太快被封IP。

2. 编码不同导致的文件写入失败

在写入文件时,由于存在不同的编码,常常导致文件写入失败,在最开始我转换编码为 utf-8 ,后来发现这个编码在excel里面居然是乱码,于是改为 gbk 编码。

  1. with open('CNKI_res.tsv', 'a', encoding='gbk') as f:
  2. f.write(res)

3. xpath 地址经常发生改变

由于知网中包含着不同类型的文献,如期刊、硕博、会议、专利 等,xpath的位置不是一成不变的,虽然xpath唯一定位的特性便于我们找到相应的标签。但偶尔class name 或许是更好的选择。

四、后记

在数据分析中,往往花费时间的事数据的获取和数据清洗,怎样从互联网海量的数据中高效获取我们想要的部分?无疑网络爬虫是最佳的选择之一。学习好爬虫的相关库的运用,不论是从或联网上获取相关的数据,还是设置某些东东提交任务,甚至是写一些抢票软件都不是什么困难的事情。

另一方面,爬虫与网站的反爬系统一直都是攻防的双方,Selenium 这类软件能够直接模拟浏览器操作,进而绕过一些反爬机制,但并不是不能够被网站识别。在真实的情况中,我们往往需要结合多种手段爬取网页。

在这场爬虫和反爬虫的军备竞赛中;在人与计算机的竞赛中,我们只有不断地学习新的东西,才能在这场进化中不被淘汰。

 
如果本文对你有帮助,别忘记给我个3连 ,点赞,转发,评论,
关注与私信博主(222)学习更多pytho知识与技巧,课件,源码,安装包,还有最新大厂面试资料等等等
咱们下期见。
收藏 等于白嫖,点赞才是真情。

 

 

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发