上一篇谈到了如何爬取知网的论文标题和论文作者,这一篇讲一下如何爬取多页,以及如何爬取作者的详细信息。
1. 换页
同样的,我们在搜索结果页按下F12查看网页源代码,将光标定位到翻页按钮上;
可以看到每一页对应一个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
上图的url为:
再点进另一个作者页看一下,其url为:
对比两者可以发现他们的skey、code和v这三个参数不同,由此可知这三个参数影响着你访问的页面内容,其中skey就是当前的作者名。
我们回到搜索结果页,同样F12查看源代码,将光标定位到某个作者名上:
从上图中可以看到,href属性的scode和acode就是上述我们需要的code参数,可是这个v参数是什么呢,这里也没有给出,我们先将skey和code这两个参数替换到url中试一下,如找到作者陈恒
从中拿出skey=陈恒,code=29972400,放入刚才的url中。
可以看到,我们成功访问到了陈恒这个作者的详细信息。那么接下来我们就可以取出每一个作者的名字和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:
可以看到作者的大学和专业分别对应了第一个和第二个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()
我爬到的数据: