Python爬虫——爬取知网论文数据(二)

接上一篇,Python爬虫——爬取知网论文数据(一)

上一篇谈到了如何爬取知网的论文标题和论文作者,这一篇讲一下如何爬取多页,以及如何爬取作者的详细信息。

1. 换页

同样的,我们在搜索结果页按下F12查看网页源代码,将光标定位到翻页按钮上;
Python爬虫——爬取知网论文数据(二)
可以看到每一页对应一个a标签,我们复制出这些a标签的选择器来看一下:

#page2	#第二页的selector
#page3	#第三页的selector
#page4	#第四页的selector

很显然,他们的selector只变了后面的数字,这个数字就是页数。根据这个规律就可以写出一个换页的函数:

# pn表示当前要爬的页数
def change_page(driver, pn):
    driver.find_element_by_css_selector('#page' + str(pn)).click()
    time.sleep(5)
    content = driver.page_source.encode('utf-8')
    soup = BeautifulSoup(content, 'lxml')
    return soup

每次爬取完一页之后就可以调用这个函数切换到下一页,再次爬取下一页的内容。

2. 爬取作者详细信息
首先我们点进某个作者的页面,到地址栏查看url
Python爬虫——爬取知网论文数据(二)
上图的url为:
Python爬虫——爬取知网论文数据(二)

再点进另一个作者页看一下,其url为:Python爬虫——爬取知网论文数据(二)

对比两者可以发现他们的skey、code和v这三个参数不同,由此可知这三个参数影响着你访问的页面内容,其中skey就是当前的作者名。

我们回到搜索结果页,同样F12查看源代码,将光标定位到某个作者名上:
Python爬虫——爬取知网论文数据(二)
从上图中可以看到,href属性的scode和acode就是上述我们需要的code参数,可是这个v参数是什么呢,这里也没有给出,我们先将skey和code这两个参数替换到url中试一下,如找到作者陈恒
Python爬虫——爬取知网论文数据(二)
从中拿出skey=陈恒,code=29972400,放入刚才的url中。
Python爬虫——爬取知网论文数据(二)

可以看到,我们成功访问到了陈恒这个作者的详细信息。那么接下来我们就可以取出每一个作者的名字和a标签href属性的scode值,来作为url的skey和code参数。
代码如下:

# 获取作者详情页url的skey和code, 传入参数是一个a标签
def get_skey_code(a):
    skey = a.get_text().strip()
    href = str(a.get('href'))    # 拿到a标签href的值
    code = href[href.find('acode') + 6:]    # 拿到code的值
    return skey, code

上述代码中传入的a标签在上一篇Python爬虫——爬取知网论文数据(一)中有讲,就是包含作者名的a标签。

现在我们拿到了访问作者详情页的url,要获取作者的信息就很方便了,以陈恒作者为例,在详情页按下F12:
Python爬虫——爬取知网论文数据(二)
可以看到作者的大学和专业分别对应了第一个和第二个H3标签,获取到这两个标签,并拿出里面的文本信息即可:

h3 = soup.find_all('h3')	# 拿到所有h3元素
college = h3[0].get_text().strip()	# 第一个h3里是大学
major =  h3[1].get_text().strip()	# 第二个h3里是专业

这样我们就拿到了作者的大学和专业信息。如果想获取更多别的信息,可以照着这个方法获取其他元素。

至此,重点部分就结束了,下面贴一下我最后的代码,做了一些封装和一些空值处理,并将爬取到的数据存入了csv文件。

'''
    知网论文数据爬取
'''

from bs4 import BeautifulSoup
from selenium import webdriver
import time
import requests
import csv


# 定义论文类
class Paper:
    def __init__(self, title, authors):
        self.title = title
        self.authors = authors

# 定义作者类
class Author:
    def __init__(self,name, college, major):
        self.name = name
        self.college = college
        self.major = major


# 进入知网首页并搜索关键词
def driver_open(driver, key_word):
    url = "https://www.cnki.net/"
    driver.get(url)
    time.sleep(2)
    driver.find_element_by_css_selector('#txt_SearchText').send_keys(key_word)
    time.sleep(2)
    # 点击搜索按钮
    driver.find_element_by_css_selector('body > div.wrapper.section1 > div.searchmain > div > div.input-box > input.search-btn').click()
    time.sleep(5)
    content = driver.page_source.encode('utf-8')
    # driver.close()
    soup = BeautifulSoup(content, 'lxml')
    return soup

def spider(driver, soup, papers):
    tbody = soup.find_all('tbody')
    tbody = BeautifulSoup(str(tbody[0]), 'lxml')
    tr = tbody.find_all('tr')
    for item in tr:
        tr_bf = BeautifulSoup(str(item), 'lxml')

        td_name = tr_bf.find_all('td', class_ = 'name')
        td_name_bf = BeautifulSoup(str(td_name[0]), 'lxml')
        a_name = td_name_bf.find_all('a')
        # get_text()是获取标签中的所有文本,包含其子标签中的文本
        title = a_name[0].get_text().strip()
        print("title : " + title)


        td_author = tr_bf.find_all('td', class_ = 'author')
        td_author_bf = BeautifulSoup(str(td_author), 'lxml')
        a_author = td_author_bf.find_all('a')
        authors = []
        # 拿到每一个a标签里的作者名
        for author in a_author:
            skey, code = get_skey_code(author)  # 获取作者详情页url的skey和code
            name = author.get_text().strip()    # 获取学者的名字
            print('name : ' + name)
            college, major = get_author_info(skey, code)  # 在作者详情页获取大学和专业, major是一个数组
            au = Author(name, college, major)   # 创建一个学者对象
            authors.append(au)

        print('\n')
        paper = Paper(title, authors)
        papers.append(paper)
        time.sleep(1)   # 每调一次spider休息1s


# pn表示当前要爬的页数
def change_page(driver, pn):
    driver.find_element_by_css_selector('#page' + str(pn)).click()
    time.sleep(5)
    content = driver.page_source.encode('utf-8')
    soup = BeautifulSoup(content, 'lxml')
    return soup

# 获取作者详情页url的skey和code, 传入参数是一个a标签
def get_skey_code(a):
    skey = a.get_text().strip()
    href = str(a.get('href'))    # 拿到a标签href的值
    code = href[href.find('acode') + 6:]    # 拿到code的值
    return skey, code

# 获取作者的详细信息
def get_author_info(skey, code):
    url = 'https://kns.cnki.net/kcms/detail/knetsearch.aspx?dbcode=CAPJ&sfield=au&skey=' + skey + '&code=' + code + '&v=3lODiQyLcHhoPt6DbD%25mmd2FCU9dfuB5GXx8ZJ7nSrKZfD6N9B5gKP9Ftj%25mmd2B1IWA1HQuWP'
    header = {
        'user-agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.133 Safari/569.36',
        'Connection': 'close'
    }
    requests.packages.urllib3.disable_warnings()
    rsp = requests.get(url, headers = header, verify = False)
    rsp_bf = BeautifulSoup(rsp.text, 'lxml')
    div = rsp_bf.find_all('div', class_ = 'wrapper')
    # 有的学者查不到详细信息
    if div:
        div_bf = BeautifulSoup(str(div[0]), 'lxml')
        h3 = div_bf.find_all('h3')
        college = h3[0].get_text().strip()
        major = h3[1].get_text().strip()
        # major = major.split(';')[0: -1]
        print('college:' + college)
        print('major: ' + major)
        return college, major
    print("无详细信息")
    return None, None

if __name__ == '__main__':
    driver = webdriver.Chrome("D:/Software/chorme/chromedriver.exe")
    soup = driver_open(driver, '知识图谱')  # 搜索知识图谱
    papers = []     # 用于保存爬取到的论文
    # 将爬取到的论文数据放入papers中
    spider(driver, soup, papers)
    for pn in range(2, 31):
        content = change_page(driver, pn)
        spider(driver, content, papers)
    driver.close()


    # 写入文件
    f_papers_authors = open('./paper_author.csv', 'w', encoding = 'utf-8', newline = '')
    writer_p_a = csv.writer(f_papers_authors)  # 基于文件对象构建 csv写入对象
    writer_p_a.writerow(["name", "college", "major", "paper"])    # csv文件的表头
    
    # 读取每一篇论文
    for paper in papers:
        # 写入paper_author.csv文件
        for author in paper.authors:
            if author.name:
                # print(author + "  ")
                writer_p_a.writerow([author.name, author.college, author.major, paper.title])

    # 关闭文件
    f_papers_authors.close()

我爬到的数据:
Python爬虫——爬取知网论文数据(二)

上一篇:MySQL关联两张表 常用的几种方法


下一篇:python爬虫入门学习3 批量爬取小说并生成文件