赞
踩
临近期末,写论文的时候到了,这个时候就需要从知网查找大量的文献。但去知网一条一条进去看摘要又略显麻烦和浪费时间。于是,反手写一个爬虫,批量获取基本信息,岂不美哉?
在开始这个项目之前,我抱着不重复造轮子的心态,寻思着去Github先找找。结果发现基本上都是几年前的项目,现在早已不能使用。最后证实了,靠别人不如靠自己,撸起袖子就开干!
网络爬虫就是模拟浏览器发送网络请求,接收请求响应,一种按照一定的规则,自动地抓取互联网信息的程序。
目前爬虫主要分为以 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来爬取知网。
Selenium支持非常多的浏览器,如Chrome、Firefox、Edge等,我们只要首先下载好相应浏览器的webdriver到python主目录中,或者加入环境变量即可。
不同浏览器的初始化:
from selenium import webdriver
browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.Safari()
我们可以用get()方法来请求一个网页,传入参数链接URL
browser.get('https://www.bing.com')
find_element_by_id()
find_element_by_name()
find_element_by_class_name()
find_element_by_tag_name()
find_element_by_link_text()
find_element_by_partial_link_text()
find_element_by_xpath()
find_element_by_css_selector()
在element变成elements就是找所有满足的条件,返回数组。
另外,我经常使用的查找元素方法为selenium中selenium.webdriver.common.by的By, 联合隐士等待EC
用法如下:
# 单个元素
WebDriverWait( driver, 10 ).until( EC.presence_of_element_located((By.XPATH ,"") ) )
# 多个元素
WebDriverWait( driver, 10 ).until( EC.presence_of_all_elements_located( (By.CLASS_NAME ,"fz14") ) )
# 元素类型有:
CLASS_NAME = 'class name'
CSS_SELECTOR = 'css selector'
ID = 'id'
LINK_TEXT = 'link text'
NAME = 'name'
PARTIAL_LINK_TEXT = 'partial link text'
TAG_NAME = 'tag name'
XPATH = 'xpath'
在找到相应元素位置后,我们常用的交互动作包括:点击、输入、清楚、获取属性、获取文本等
element = find_element_by_id(''id)
element.send_keys('Hello') # 传入Hello
element.clear() # 清除输入框
element.click() # 点击元素
element.text # 获取元素文本信息
element.get_attribute('href') # 获取元素属性
还有大量的方法这里没有提及,不过有了以上基本知识,我们就可以开始项目了!
知网首页中,我们仅需要先在输入框中键入主题词,然后点击搜索图标,即可跳转到结果页面。
我们通过浏览器的检查页面,得到输入框和搜索图标的XPATH分别为:
input_xpath = '/html[1]/body[1]/div[1]/div[2]/div[1]/div[1]/input[1]'
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 定位到下载链接,其他元素同理。
完成以上知网页面的分析后,我们就可以根据需求开始写代码了!
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
这里我们创建一个Chrome浏览器的窗口,并设置相关参数:
#get直接返回,不再等待界面加载完成 desired_capabilities = DesiredCapabilities.CHROME desired_capabilities["pageLoadStrategy"] = "none" # 设置谷歌驱动器的环境 options = webdriver.ChromeOptions() # 设置chrome不加载图片,提高速度 options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2}) # 设置不显示窗口 #options.add_argument('--headless') # 创建一个谷歌驱动器 driver = webdriver.Chrome(options=options) # 设置搜索主题 theme = "Python" # 设置所需篇数 papers_need = 100
# 打开页面 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[1]/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[5]/div[1]/div/div/div/a[1]") ) ).click() time.sleep(1) # 获取总文献数和页数 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 # 去除千分位里的逗号 res_unm = int(res_unm.replace(",",'')) page_unm = int(res_unm/20) + 1 print(f"共找到 {res_unm} 条结果, {page_unm} 页。")
# 赋值序号, 控制爬取的文章数量 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: term = count%20 # 本页的第几个条目 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]" 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]" 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]" 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]" 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]" 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]) # 开始获取页面信息 # 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[1]/body[1]/div[2]/div[1]/div[3]/div[1]/div[1]/div[3]/div[1]/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] except: keywords = '无' url = driver.current_url # 获取下载链接 # link = WebDriverWait( driver, 10 ).until( EC.presence_of_all_elements_located((By.CLASS_NAME ,"btn-dlcaj") ) )[0].get_attribute('href') # link = urljoin(driver.current_url, link) # 写入文件 res = f"{count}\t{title}\t{authors}\t{institute}\t{date}\t{source}\t{database}\t{keywords}\t{abstract}\t{url}".replace("\n","")+"\n" print(res) with open('CNKI_res.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]) # 计数,判断需求是否足够 count += 1 if count == papers_need:break # 切换到下一页 WebDriverWait( driver, 10 ).until( EC.presence_of_element_located( (By.XPATH ,"//a[@id='PageNext']") ) ).click() # 关闭浏览器 driver.close()
至此,所有功能都已实现,代码中写了详细的注释。
结果是一个以制表符分隔的表格文件,其中包含了论文的基本信息,包括:题目、作者、来源、摘要、链接等
有时候我们并不需要网页完全,我们想要的信息已经加载出来,于是加上以下设置:
#get直接返回,不再等待界面加载完成
desired_capabilities = DesiredCapabilities.CHROME
desired_capabilities["pageLoadStrategy"] = "none"
另一方面,在适当的地方加上 time.sleep(3) 延时几秒,既可以等待页面加载,也可以防止爬取太快被封IP。
在写入文件时,由于存在不同的编码,常常导致文件写入失败,在最开始我转换编码为 utf-8 ,后来发现这个编码在excel里面居然是乱码,于是改为 gbk 编码。
with open('CNKI_res.tsv', 'a', encoding='gbk') as f:
f.write(res)
由于知网中包含着不同类型的文献,如期刊、硕博、会议、专利 等,xpath的位置不是一成不变的,虽然xpath唯一定位的特性便于我们找到相应的标签。但偶尔class name 或许是更好的选择。
在数据分析中,往往花费时间的事数据的获取和数据清洗,怎样从互联网海量的数据中高效获取我们想要的部分?无疑网络爬虫是最佳的选择之一。学习好爬虫的相关库的运用,不论是从或联网上获取相关的数据,还是设置某些东东提交任务,甚至是写一些抢票软件都不是什么困难的事情。
另一方面,爬虫与网站的反爬系统一直都是攻防的双方,Selenium 这类软件能够直接模拟浏览器操作,进而绕过一些反爬机制,但并不是不能够被网站识别。在真实的情况中,我们往往需要结合多种手段爬取网页。
在这场爬虫和反爬虫的军备竞赛中;在人与计算机的竞赛中,我们只有不断地学习新的东西,才能在这场进化中不被淘汰。
以上就是今天的全部内容分享,觉得有用的话欢迎点赞收藏哦!
学好 Python 不论是用于就业还是做副业赚钱都不错,而且学好Python还能契合未来发展趋势——人工智能、机器学习、深度学习等。
小编是一名Python开发工程师,自己整理了一套最新的Python系统学习教程,包括从基础的python脚本到web开发、爬虫、数据分析、数据可视化、机器学习等。如果你也喜欢编程,想通过学习Python转行、做副业或者提升工作效率,这份【最新全套Python学习资料】 一定对你有用!
小编为对Python感兴趣的小伙伴准备了以下籽料 !
对于0基础小白入门:
如果你是零基础小白,想快速入门Python是可以考虑培训的!
包括:Python激活码+安装包、Python web开发,Python爬虫,Python数据分析,人工智能、机器学习、Python量化交易等学习教程。带你从零基础系统性的学好Python!
Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
最新全套【Python入门到进阶资料 & 实战源码 &安装工具】(安全链接,放心点击)
我已经上传至CSDN官方,如果需要可以扫描下方官方二维码免费获取【保证100%免费】
*今天的分享就到这里,喜欢且对你有所帮助的话,记得点赞关注哦~下回见 !
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。