内容简介:最近要写一个数据分析的项目,需要根据关键词爬取近十年期刊的主要信息,记录一下爬取过程中遇到的问题cnki算是对爬虫作了一定抵御,我们要爬取学术论文详情页的主题,摘要等信息,主要步骤和其他网站的爬取大致相似:一是要根据关键词搜索到列表页;二是要从列表页请求得到详情页,从详情页取得我们所要的信息。欢迎fork我的Github项目
- 【python2.7】爬取知网论文
- python实现CNKI知网爬虫
- 《Python3网络爬虫开发实战》崔庆才
最近要写一个数据分析的项目,需要根据关键词爬取近十年期刊的主要信息,记录一下爬取过程中遇到的问题
分析
cnki算是对爬虫作了一定抵御,我们要爬取学术论文详情页的主题,摘要等信息,主要步骤和其他网站的爬取大致相似:一是要根据关键词搜索到列表页;二是要从列表页请求得到详情页,从详情页取得我们所要的信息。
-
入口页面:[ kns.cnki.net/kns/brief/d… ]
-
搜索后,js动态渲染的请求列表页面:[ kns.cnki.net/kns/brief/b… ..] 这里我们打开Developer Tools观察请求头和参数
这里的关键信息: ① 请求参数 ,我们观察到请求的关键词在字段KeyValue中(GET请求); ② cookie 和 referer :如果没有在请求头部加入referer,我们将无法打开这个列表页,如果没有在头部中加入cookie,我们请求后得到的页面内容是不完整的!注意:iframe列表详情页只有从入口页面请求渲染后才能得到,这步请求不能省略! -
从列表页的链接中解析得到详情页[ kns.cnki.net/KCMS/detail… ...]
我们继续打开Developer Tools观察网页的HTML中跳转到详情页的链接 这里我们发现,链接的地址和我们最终得到的地址是不同的!是因为网页重定向了! -
详情页,这里就只要解析网页即可,我们通过xpath可以很容易得到题目,作者,关键词,摘要等信息
Scrapy实战
-
如何设置cookie:
- settings中设置
COOKIES_ENABLED=True
; - http请求参考 Scrapy - how to manage cookies/sessions
- 补充:cookiejar模块的主要作用是提供可存储的cookie对象,可以捕获cookie并在后续连接请求时重新发送,实现模拟登录功能。在scrapy中可以在请求是传入meta参数设置,根据不同会话记录对应的cookie:
- settings中设置
-
如何请求入口页:(CJFQ代表期刊,可根据需求更改)
data = { "txt_1_sel": "SU$%=|", "txt_1_value1": self.key_word, "txt_1_special1": "%", "PageName": "ASP.brief_default_result_aspx", "ConfigFile": "SCDBINDEX.xml", "dbPrefix": "CJFQ", "db_opt": "CJFQ", "singleDB": "CJFQ", "db_codes": "CJFQ", "his": 0, "formDefaultResult": "", "ua": "1.11", "__": time.strftime('%a %b %d %Y %H:%M:%S') + ' GMT+0800 (中国标准时间)' } query_string = parse.urlencode(data) yield Request(url=self.home_url+query_string, headers={"Referer": self.cur_referer}, cookies={CookieJar: 1}, callback=self.parse) 复制代码
- 如何请求列表页
def parse(self, response): data = { 'pagename': 'ASP.brief_default_result_aspx', 'dbPrefix': 'CJFQ', 'dbCatalog': '中国学术期刊网络出版总库', 'ConfigFile': 'SCDBINDEX.xml', 'research': 'off', 't': int(time.time()), 'keyValue': self.key_word, 'S': '1', "recordsperpage": 50, # 'sorttype': "" } query_string = parse.urlencode(data) url = self.list_url + '?' + query_string yield Request(url=url, headers={"Referer": self.cur_referer}, callback=self.parse_list_first) 复制代码
- 如何解析列表页
- 获得列表总页数:
response.xpath('//span[@class="countPageMark"]/text()').extract_first() max_page = int(page_link.split("/")[1]) 复制代码
- 请求每个列表页
data = { "curpage": page_num,#循环更改 "RecordsPerPage": 50, "QueryID": 0, "ID":"", "turnpage": 1, "tpagemode": "L", "dbPrefix": "CJFQ", "Fields":"", "DisplayMode": "listmode", "PageName": "ASP.brief_default_result_aspx", "isinEn": 1 } 复制代码
- 解析列表页(这里如果结果为空,请检查你是否正确设置了cookie)
tr_node = response.xpath("//tr[@bgcolor='#f6f7fb']|//tr[@bgcolor='#ffffff']") for item in tr_node: paper_link = item.xpath("td/a[@class='fz14']/@href").extract_first() 复制代码
- 如何解析详情页(只是一个示例,有很多种解析方法)
title = response.xpath('//*[@id="mainArea"]/div[@class="wxmain"]/div[@class="wxTitle"]/h2/text()').extract() author = response.xpath('//*[@id="mainArea"]/div[@class="wxmain"]/div[@class="wxTitle"]/div[@class="author"]/span/a/text()').extract() abstract = response.xpath('//*[@id="ChDivSummary"]/text()').extract() keywords = response.xpath('//*[@id="catalog_KEYWORD"]/following-sibling::*/text()').extract() 复制代码
欢迎fork我的Github项目
2018.12.15 更新
上面项目在爬取数量不多的项目时不会报错,但是我尝试爬取20w数据量的论文时,发现每次只有1000多条数据,观察发现请求转到 vericode.aspx
页,即验证码页面。因为我不怎么会处理验证码啦,所以果断放弃,使用手机知网的接口 wap.cnki.net/touch/web ,发现真的so easy!
-
请求列表页
第一步还是要观察请求,打开DevTool
可以简单的构造第一个请求(GET):
def start_requests(self): data = { "kw": self.key_word, "field":5 } url = self.list_url + '?' + parse.urlencode(data) yield Request(url=url, headers=self.header, meta={'cookiejar': 1}, callback=self.parse) 复制代码
-
得到第一页列表页,筛选条件,得到请求的FormData
我们在网页进行筛选操作,可以看到类似结果:
FormData中,我们可以复制下来后,修改的几个变量来进行筛选:- pageindex:第几页列表页(1 ~ )
- fieldtype: 主题/篇名/全文/作者/关键词/单位/摘要/来源
- sorttype: 相关度/下载次数/被引频次/最新文献/历史文献
- articletype:文献类型
- starttime_sc: 开始年份
- endtime_sc: 结束年份
def parse(self, response): self.header['Referer'] = response.request.url yield FormRequest(url=self.list_url, headers = self.header, method = 'POST', meta = {'cookiejar': 1}, formdata = self.myFormData, callback = self.parse_list, dont_filter = True) 复制代码
-
解析得到总列表页数,并构造请求
#总页数 paper_size = int(response.xpath('//*[@id="totalcount"]/text()').extract_first()) #构造请求 for page in range(1, paper_num): self.myFormData["pageindex"] = str(page), yield FormRequest(url=self.list_url, headers = self.header, method = 'POST', meta = {'cookiejar': page+1, 'page': page},#更新会话 formdata = self.myFormData, callback = self.parse_list_link, dont_filter = True) 复制代码
注意:我们观察请求过程,在网页中我们是通过点击更新的,我们观察LoadNextPage函数,可以看到请求更新数据也是通过提交表单的方式,因此我们可以构造POST请求数据。
-
请求详情页
items = response.xpath('//a[@class="c-company-top-link"]/@href').extract() #可以将已爬取详情页数写入文件进行记录 with open('../record_page.txt', 'a') as f: f.write(str(response.meta['page']) + '\n') for item in items: yield Request(url = item, meta={'cookiejar': response.meta['cookiejar']},#对应会话标志 headers = self.header, callback = self.parse_item) 复制代码
-
解析详情页(示例)
baseinfo = response.xpath('/html/body/div[@class="c-card__paper2"]') keywords = baseinfo.xpath('//div[contains(text(),"关键词")]/following-sibling::*/a/text()').extract() 复制代码
补充
为了提高爬取速度,防止ip被识别的可能,推荐阿布云进行IP代理,申请账号及HTTP动态隧道后,更改settings:
DOWNLOAD_DELAY = 0.2 DOWNLOADER_MIDDLEWARES = { 'myspider.middlewares.RandomUserAgentMiddleware': 401, 'myspider.middlewares.ABProxyMiddleware': 1, } AB_PROXY_SERVER = { 'proxyServer': "http://http-dyn.abuyun.com:9020", 'proxyUser': "xxxxxxxxxxxxxxx",#你的 'proxyPass': "xxxxxxxxxxxxxxx"#你的 } 复制代码
添加中间件:
proxyAuth = "Basic " + base64.urlsafe_b64encode(bytes((proxyUser + ":" + proxyPass), "ascii")).decode("utf8") class ABProxyMiddleware(object): """ 阿布云ip代理配置 """ def process_request(self, request, spider): request.meta["proxy"] = proxyServer request.headers["Proxy-Authorization"] = proxyAuth 复制代码
爬虫菜鸟,有问题请帮忙指出!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
标签: 爬虫
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。