今天因为需要做了一个爬取知网博硕士论文及中国专利的爬虫,在制作的过程中遇到了不少坑,在网上查资料时都是很老的资源,在现在知网的反爬虫下不起作用,所以我来写这篇文章来供大家参考。(这篇文章主要介绍通过改写获得的网址来避开知网的反爬机制,完成普通文章和以表格为主体的html代码的信息的抓取)

这篇代码主要是抓取指望中关键字为保护渣的博硕士论文以及中国专利信息,其中中国专利信息较难抓取,主要是因为专利的信息在表格中,而表格又是动态的,代码末尾处有提示如何改代码,你可以通过改写代码中key的值,改变抓取内容的关键字,也可以更改抓取的文献内容代码后面有介绍。
代码如下。(代码中每一步都注释的很清楚)

# -*- coding: utf-8 -*-
import time
import re
import random
import requests
import pymysql
from bs4 import BeautifulSoup





headers = {
    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Encoding':'gzip, deflate, sdch',
    'Accept-Language':'zh-CN,zh;q=0.8',
    'Connection':'keep-alive',
    'Host':'www.cnki.net',
    'Referer':'http://search.cnki.net/search.aspx?q=%E4%BD%9C%E8%80%85%E5%8D%95%E4%BD%8D%3a%E6%AD%A6%E6%B1%89%E5%A4%A7%E5%AD%A6&rank=relevant&cluster=zyk&val=CDFDTOTAL',
    'Upgrade-Insecure-Requests':'1',
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
}

headers1 = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
        'Connection':'keep-alive',
        'Cookie':'Ecp_ClientId=6200426191000935476; SID_sug=111054; cnkiUserKey=c53f825c-b99b-59f4-a41e-dc2604699e98; ASP.NET_SessionId=ut2fqnilpd51bjijpcaxzyfz; SID_search=201087; UM_distinctid=171b64edb7c40c-07684554dd81b4-9393265-144000-171b64edb7d643; Ecp_IpLoginFail=200427221.192.179.83; CNZZDATA2643871=cnzz_eid%3D980108062-1587900042-%26ntime%3D1587975276; CNZZDATA3636877=cnzz_eid%3D1649504557-1587900840-%26ntime%3D1587975276',
        'Host':'search.cnki.net',
        'Referer':'http://search.cnki.net/search.aspx?q=%e4%bf%9d%e6%8a%a4%e6%b8%a3&rank=relevant&cluster=all&val=',
        'Upgrade-Insecure-Requests':'1',

    }
#注意,这里一定要设置两个请求头,知网有双重检查,用自己的也行去网上找也行。



connection = pymysql.connect('localhost', 'root', '1234567', 'zhiwang',
                             charset='utf8')
cursor = connection.cursor()  # 打开mysql数据库的连接。



#下面定义一个函数来获得每一篇文章的链接并放在一个列表中。
def get_url_list(start_url):
    depth = 10#=========================================================这里可以设置爬取每一种文献的页数,一页有15条信息================================================================================
    url_list = []
    i=1
    for i in range(depth):
        try:
            url = start_url + "&p=" + str(i * 15)#分析页面网址特征,发现共同点,例如http://search.cnki.net/Search.aspx?q=%E4%BF%9D%E6%8A%A4%E6%B8%A3&rank=relevant&cluster=zyk&val=CCNDTOTAL&p=15里的15决定了你所在的页面。
            search = requests.get(url.replace('\n', ''), headers=headers1)#注意设置请求头。
            soup = BeautifulSoup(search.text, 'html.parser')
            for art in soup.find_all('div', class_='wz_tab'):
                if art.find('a')['href'] not in url_list:
                    rule = '.*aspx?(.*)'
                    url1 = re.findall(rule, art.find('a')['href'])
                    url_ture = 'https://kns.cnki.net/KCMS/detail/detail.aspx' + url1[0]
                    url_ = url_ture
                    url_list.append(url_)#将获取的网址加入到网址列表中。
                    print(url_)
                    #if下面的语句很重要,这里是将获得的网址进行转换,换成我们可以使用的网址。
            print("爬取第" + str(i) + "页成功!")
            time.sleep(random.randint(1, 3))#设置睡眠时间,防止被服务器屏蔽。
        except:
            print("爬取第" + str(i) + "页失败!")
    return url_list




#下面定义一个函数来从文章页面获得我们要提取的信息。
def get_data(url_list, wordType):
    try:
        for url in url_list:
            if url == pymysql.NULL or url == '':
                continue
            try:
                html = requests.get(url.replace('\n', ''), headers=headers)
                print(html)
                soup = BeautifulSoup(html.text, 'html.parser')
            except:
                print("获取网页失败")
            try:
                if soup is None:
                    continue
                #获取标题
                title = soup.find('title').get_text().split('-')[0]
                # 获取摘要
                summary = 0#用summary==0来判断summary是那种文献中的然后提取。
                try:
                    summary = soup.find('span', id='ChDivSummary').get_text()#博硕士论文中摘要的提取,如果不是博硕士论文则不会赋值,接下来会进入中国专利的论文提取。
                except:
                    summary=0
                if summary == 0:
                    relu = '.*?<td.*?>(.*)</td>'
                    a = soup.find_all('td', attrs={'class': 'checkItem', 'colspan': '3'})
                    summary = str(a[2]).replace('\n', '').replace(' ', '')
                    rule='<td.*?>(.*?)</td>'
                    summary = re.findall(rule,summary)[0]#中国专利的摘要提取



                if summary == 0:
                    summary = '摘要类型不符合要求'#特殊类型处理
            except:
                print("部分获取失败")
                pass
            print("【Title】:" + title)
            print("【url】:"+url)
            print("【summary】:" + summary)
            cursor.execute('INSERT INTO yingwen VALUES (%s,%s, %s)', (title, url,summary))#将获取的信息放到数据库里。
            connection.commit()

        print("爬取完毕")
    finally:
        print()


if __name__ == '__main__':
    try:
        for wordType in ["CMFDTOTAL""CDFDTOTAL""SCPD"]:#这个列表中放的是你想要爬取的文献类型(博士论文或是中国专利。)代码的末尾有对照的信息。
            key='保护渣'#改变这里可以改变你爬取文献的关键字。
            start_url = "http://search.cnki.net/search.aspx?q=%s&rank=relevant&cluster=zyk&val=%s" % (key,wordType)#拼接网址
            url_list = get_url_list(start_url)
            print("开始爬取")
            get_data(url_list, wordType)
            print("一类数据爬取完毕")
        print("全部爬取完毕")
    finally:
        connection.close()#抓取完成,关闭连接。
        '''"CDFDTOTAL":博士论文
           "CMFDTOTAL":硕士论文
           "SCPD":     中国专利'''

在爬取时要注意的的问题:

  1. 首先,要设置双请求头,请求头中信息尽量完整。
  2. 我们在网站中获得信息页的网址并不是真正的网址,例如那我们从页面中获得的详情页的网址如这个网址

http://epub.cnki.net/grid2008/brief/detailj.aspx?filename=1019146259.nh&dbname=CDFDLAST2019

这个是我们获得的网址但是我们点开之后会发现这个链接并不能直接进入详情页,而是跳转到了首页,
在这里插入图片描述这说明我们需要改网址才能进入详情页,分析网址之后发现真正决定信息是后缀中的 filename=1019146259.nh&dbname=CDFDLAST2019
所以我们只要改变链接的前缀就能得到详情页真正的网址了,分析之后得到详情页真正的网址是

https://kns.cnki.net/KCMS/detail/detail.aspx?filename=1019146259.nh&dbname=CDFDLAST2019

打开之后
在这里插入图片描述

进而得到了真正的代码。
还有在爬取专利的模块时原链接

http://dbpub.cnki.net/grid2008/dbpub/detail.aspx?filename=CN105750519A&dbname=SCPD2016
打开之后是这样的在这里插入图片描述

然而在爬取时我们会发现这个网址下的页面中的摘要再爬取时频繁的发生无响应的情形,导致无法爬取(好像是因为这个摘要中的链接是动态的),这是知网的反爬虫在捣乱,但是我偶然发现如果用正则表达式将网址改为

https://kns.cnki.net/KCMS/detail/detail.aspx?filename=CN105750519A&dbname=SCPD2016

这时打开的页面是这样的在这里插入图片描述
在这个网址下爬取就不会遇到反爬的情况,我们简单的用beautifulsoup来爬取内容,并利用正则表达式来截取内容就好了。
3.爬虫的时候要设置间歇时间,爬取过快可能会被封ip.

总结一下抓取知网的难点在与它的反爬机制,首先我们应该设置双请求头,重点在于网址的修改,我们要把我们直接爬取到的网址进行修改后才能用于使用,对网址进行分析时要注意网址的后缀(例如aspx?filename=CN105750519A&dbname=SCPD2016)决定了打开网址的内容,而网址的前缀(例如https://kns.cnki.net/KCMS/detail/detail.aspx?)决定了打开的位置,我们要通过改变前缀来更改网址,后缀不能改,从而完成信息的爬取(网址分析这一部分有些词语非专业语言)
希望这篇文章对你有用,如果在阅读中遇到了任何的问题,欢迎留言讨论。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐