爬取中国知网CNKI的遇到的坑与技术总结

栏目: Python · 发布时间: 5年前

内容简介:最近要写一个数据分析的项目,需要根据关键词爬取近十年期刊的主要信息,记录一下爬取过程中遇到的问题cnki算是对爬虫作了一定抵御,我们要爬取学术论文详情页的主题,摘要等信息,主要步骤和其他网站的爬取大致相似:一是要根据关键词搜索到列表页;二是要从列表页请求得到详情页,从详情页取得我们所要的信息。欢迎fork我的Github项目

最近要写一个数据分析的项目,需要根据关键词爬取近十年期刊的主要信息,记录一下爬取过程中遇到的问题

分析

cnki算是对爬虫作了一定抵御,我们要爬取学术论文详情页的主题,摘要等信息,主要步骤和其他网站的爬取大致相似:一是要根据关键词搜索到列表页;二是要从列表页请求得到详情页,从详情页取得我们所要的信息。

  • 入口页面:[ kns.cnki.net/kns/brief/d… ]

  • 搜索后,js动态渲染的请求列表页面:[ kns.cnki.net/kns/brief/b… ..] 这里我们打开Developer Tools观察请求头和参数

    爬取中国知网CNKI的遇到的坑与技术总结
    爬取中国知网CNKI的遇到的坑与技术总结
    爬取中国知网CNKI的遇到的坑与技术总结
    这里的关键信息: ① 请求参数 ,我们观察到请求的关键词在字段KeyValue中(GET请求); ② cookiereferer :如果没有在请求头部加入referer,我们将无法打开这个列表页,如果没有在头部中加入cookie,我们请求后得到的页面内容是不完整的!注意:iframe列表详情页只有从入口页面请求渲染后才能得到,这步请求不能省略!
  • 从列表页的链接中解析得到详情页[ kns.cnki.net/KCMS/detail… ...]

    爬取中国知网CNKI的遇到的坑与技术总结
    我们继续打开Developer Tools观察网页的HTML中跳转到详情页的链接
    爬取中国知网CNKI的遇到的坑与技术总结
    爬取中国知网CNKI的遇到的坑与技术总结
    这里我们发现,链接的地址和我们最终得到的地址是不同的!是因为网页重定向了!
  • 详情页,这里就只要解析网页即可,我们通过xpath可以很容易得到题目,作者,关键词,摘要等信息

Scrapy实战

  1. 如何设置cookie:

    • settings中设置 COOKIES_ENABLED=True
    • http请求参考 Scrapy - how to manage cookies/sessions
    • 补充:cookiejar模块的主要作用是提供可存储的cookie对象,可以捕获cookie并在后续连接请求时重新发送,实现模拟登录功能。在scrapy中可以在请求是传入meta参数设置,根据不同会话记录对应的cookie:
  2. 如何请求入口页:(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)
复制代码
  1. 如何请求列表页
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)
复制代码
  1. 如何解析列表页
    • 获得列表总页数:
    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()
    复制代码
  2. 如何解析详情页(只是一个示例,有很多种解析方法)
    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!

  1. 请求列表页

    第一步还是要观察请求,打开DevTool

    爬取中国知网CNKI的遇到的坑与技术总结
    爬取中国知网CNKI的遇到的坑与技术总结

    可以简单的构造第一个请求(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)
复制代码
  1. 得到第一页列表页,筛选条件,得到请求的FormData

    我们在网页进行筛选操作,可以看到类似结果:

    爬取中国知网CNKI的遇到的坑与技术总结
    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)
    复制代码
  2. 解析得到总列表页数,并构造请求

    #总页数
    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请求数据。

    爬取中国知网CNKI的遇到的坑与技术总结
    爬取中国知网CNKI的遇到的坑与技术总结
  3. 请求详情页

    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)
    复制代码
  4. 解析详情页(示例)

    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
复制代码

爬虫菜鸟,有问题请帮忙指出!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

标签: 爬虫

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

爆品战略

爆品战略

金错刀 / 北京联合出版公司 / 2016-7-1 / 56.00

◆ 划时代的商业著作!传统企业转型、互联网创业的实战指南! ◆ 爆品是一种极端的意志力,是一种信仰,是整个企业运转的灵魂! ◆ 小米创始人雷军亲自作序推荐!小米联合创始人黎万强、分众传媒创始人江南春、美的董事长方洪波、九阳董事长王旭宁等众多一线品牌创始人联袂推荐! ◆ 创图书类众筹新纪录!众筹上线2小时,金额达到10万元;上线1星期,金额突破100万元! ◆ 未售......一起来看看 《爆品战略》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试