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

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

内容简介:最近要写一个数据分析的项目,需要根据关键词爬取近十年期刊的主要信息,记录一下爬取过程中遇到的问题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
复制代码

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


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

标签: 爬虫

猜你喜欢:

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

Code Reading

Code Reading

Diomidis Spinellis / Addison-Wesley Professional / 2003-06-06 / USD 64.99

This book is a unique and essential reference that focuses upon the reading and comprehension of existing software code. While code reading is an important task faced by the vast majority of students,......一起来看看 《Code Reading》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具