python爬取知网的数据进行各计算机领域学术关注度指数的可视化
最近在思考人生,逛知网时发现知网会对每个科研关键词进行统计,给出一个关注度曲线。
于是我就查看一些关键词的研究发展情况,但是每一次都要自己更换搜索关键词,再点击进去查看曲线。
作为计算机系的学生,这固然不能忍。
于是我决定用python把感兴趣的关键词的数据全部爬取下来绘制到一张图里。
效果如图:
简单记录下,下面是步骤:
一、爬取数据
1.1. 数据来源
点开一篇论文,会看见摘要下方的关键词
随便点击一个关键词,就会看到知网已经统计好的关注度指数分析。
当我们鼠标聚焦曲线时,就会看见弹窗中显示的改点的年份与数据。这里的数据就是该关键词在该年份的关注度指数,或者说该年发表的与该关键词相关的论文数量。
1.2. 爬取源码
1.2.1. 分析链接
数据找到了,我们观察本页面的链接
https://kns.cnki.net/kcms/detail/knetsearch.aspx?sfield=kw&skey=%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F&code=&v=-7Yty5Rksx3cmKbdO0sTT1XnIRr43Xy2xHdd7lZluh_xKEB2Dv_u2akX9YnCHba8
链接很长,url中所含的参数比较多,我们去掉一些不相关参数,只留下skey="推荐系统"这个关键词试试:
https://kns.cnki.net/kcms/detail/knetsearch.aspx?sfield=kw&skey=%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F
在浏览器输入,发现依旧能够获取数据。那么我们只需要替换skey=" "里面的关键词,就可以得到不同关键词的关注度指数页了。
注:url中 skey=“推荐系统” 与 skey=%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F 是等价的,只是在浏览器输入时会转码。
很好!此时再定位数据所在的标签就好了!浏览器点击F12打开审查元素,耐心寻找。发现数据就在一个有关键字“renderLineChart”的json数据里。
1.2.2. 爬取页面数据
这时,我们迫不及待的准备爬取页面再拿到数据
import requests
if __name__ == '__main__':
url="https://kns.cnki.net/kcms/detail/knetsearch.aspx?sfield=kw&skey=推荐系统"
response = requests.get(url)
print(response.content.decode('utf-8'))
请求成功了!在结果里搜索“renderLineChart”,发现找不到!这时候挠掉了几根头发。
显然,爬取数据失败了。
为什么失败?可能是该数据并不是静态存储在doc中的,而是动态获取的。
1.2.3. 解决爬取js动态数据问题
这时候回到浏览器f12界面。点击网络(network),刷新页面,会发现所有的数据请求都在这个列表里。226条请求如何找到我需要的数据请求呢?
“数据就在一个有关键字“renderLineChart”的json数据里” 在网络页面ctrl+f搜索:renderLineChart。
浏览器就自动帮我们定位请求所在位置了。
此时我们点击“标头”,就可以看到浏览器告诉我们的请求URL。
链接如下:
https://kns.cnki.net/kcms/detail/frame/knetlist.aspx?name=%e6%8e%a8%e8%8d%90%e7%b3%bb%e7%bb%9f&infotype=9&codetype=j&catalogName=%E5%85%B3%E6%B3%A8%E5%BA%A6%E6%8C%87%E6%95%B0%E5%88%86%E6%9E%90&vl=-7Yty5Rksx3cmKbdO0sTT1XnIRr43Xy2xHdd7lZluh_hb-vEEpRBDQuaXcWzE0YC
这时,我们迫不及待的准备爬取页面再拿到数据
import requests
if __name__ == '__main__':
url="https://kns.cnki.net/kcms/detail/frame/knetlist.aspx?name=推荐系统&infotype=9&codetype=j&catalogName=%E5%85%B3%E6%B3%A8%E5%BA%A6%E6%8C%87%E6%95%B0%E5%88%86%E6%9E%90&vl=-7Yty5Rksx3cmKbdO0sTT1XnIRr43Xy2xHdd7lZluh_hb-vEEpRBDQuaXcWzE0YC"
response = requests.get(url)
print(response.content.decode('utf-8'))
此时发现请求是成功的!返回的内容如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title></title>
</head>
<body>
<form name="form1" method="post" action="knetlist.aspx?name=%u63a8%u8350%u7cfb%u7edf&infotype=9&codetype=j&catalogName=%u5173%u6ce8%u5ea6%u6307%u6570%u5206%u6790&vl=-7Yty5Rksx3cmKbdO0sTT1XnIRr43Xy2xHdd7lZluh_hb-vEEpRBDQuaXcWzE0YC" id="form1">
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKLTUxMTcwNzgxMGRkjhjYRPTUl6/K/rznK1hDjhK9Xj3ZhdVm0yS5/MSd+tk=" />
<input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="30B6FF1C" />
<div>
</div>
</form>
</body>
</html>
但是为什么没有我们要的数据?这时又挠掉了几根头发。
其实就是目标网站的反爬机制了。进行数据请求时,有时候会返回一些代码,或者空白,或者缺失的数据,很可能是因为目标网站的反爬虫机制。你直接url来请求,我拒绝给你数据。
这时候就需要伪装一下了。
伪装成正常浏览器进行爬虫
伪装的方式很简单,添加假请求头fake_headers,再把fake_headers放到get()的参数里就好了。
我先是添加了cookie,发现没用。又添加了Referer就成功了。这些信息在浏览器f12界面都能找到。
#伪造浏览器请求头
#cookie = 'Ecp_ClientId=5210628102801308911;cnkiUserKey=b261114d-5456-f7a0-d218-29c90a247b35;Ecp_ClientIp=58.34.66.42;_pk_ref=%5B%22%22%2C%22%22%2C1627001927%2C%22https%3A%2F%2Fcn.bing.com%2F%22%5D;ASP.NET_SessionId=wx2bvmuixh3bq3r5meb5tnk5;SID_kns8=123123;CurrSortFieldType=desc;SID_kcms=124101;CurrSortField=%e5%8f%91%e8%a1%a8%e6%97%b6%e9%97%b4%2f(%e5%8f%91%e8%a1%a8%e6%97%b6%e9%97%b4%2c%27TIME%27);Ecp_IpLoginFail=21072358.34.66.42, 10.210.0.12;_pk_id=fc0ebc8f-840b-44c6-b064-37d1205b7bcc.1624847325.3.1627002597.1627001927.;SID_kns_new=kns123110;'
fake_headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36',
#'Cookie':cookie, #cookie测试,不需要cookie也可获取
#'Referer':'https://kns.cnki.net/kcms/detail/knetsearch.aspx?sfield=kw&skey=%E5%8C%BA%E5%9D%97%E9%93%BE&code=&v=9tzIsR7LVgUKQ_Ucqcy13H0PVvC_8a71XDfdwE8ntLnmoNnjXXC3V0UrNnvhguYG'
'c':'https://www.cnki.net/' #Referer测试,需要Referer,否则获取值为空
}
response = requests.get(targetUrl,headers =fake_headers)
伪装的很完美,数据就在我们的返回值里了。结果:
<html>
<head>
...省略
</head>
<body onload="ResezeParent(0);SetParentCatalog(); closePopMore(1)"><script type="text/javascript" src="https://piccache.cnki.net/kdn/kcms8/detail/js/min/WideScreen.min.js"></script><h2 class="title1" id="catalog_GZDZSFX">
关注度指数分析 <span class="desc">(检索范围:源数据库,包括期刊库、博士论文库、硕士论文库、报纸库、会议库)</span></h2>
<div class="titleSide"><a class="more" onclick="TurnPageToKnsApp('cidx')">
查看更多指数分析结果
</a