《人民日报》爬虫文章爬取关键词的搜索结果
优采云 发布时间: 2021-06-09 04:48《人民日报》爬虫文章爬取关键词的搜索结果
上一期《人民日报》的爬虫文章发布了,收到了很好的反馈。文章中的爬虫代码确实帮助了很多人。我很高兴。
在和读者交流的过程中,我也发现了一些比较常见的需求,就是根据关键词过滤news文章。
一开始我的想法是在爬取所有文章数据的基础上遍历文件夹,然后过滤掉body中收录关键词的文章。
如果你下载了完整的新闻资料,这个方法无疑是最方便快捷的。但如果不是,那么先爬取所有数据,再筛选符合条件的数据无疑是浪费时间。
本文文章我将介绍两种方法,一种是根据关键词过滤已有数据,另一种是利用人民网的搜索功能对关键词的搜索进行爬取结果。
1. 爬取关键词搜索结果
最近有读者问我问题,我发现人民网有搜索功能()。
所以就按照关键词搜索,然后往下爬搜索结果。
1.1 分析页面
这里简单教大家分析网页的大体思路。
1.1.1 分析网页主要看什么1.1.2 如何使用浏览器的开发者工具
具体操作也很简单。按F12打开开发者工具,切换到网络,刷新网页。可以看到列表中有很多请求。
有图片、js代码、css样式、html源代码等各种请求
点击对应的请求项后,您可以在Preview或Response中预览请求的数据内容,看是否收录您需要的数据。
当然可以一一检查,也可以使用顶部的过滤器过滤请求类型(一般情况下,我们需要的数据可以在XHR和Doc中找到)
找到对应的请求后,可以切换到headers查看请求的请求头信息。
如图所示,主要有四个重点领域。
请求 URL:请求的链接。爬虫请求的url需要在这里读取。不要只复制浏览器地址栏中的 URL。请求方法:有两种类型的请求方法:GET 和 POST。爬虫代码中是使用requests.get()还是requests.post()要与此一致,否则可能无法正确获取数据。请求头:请求头,服务器将使用它来确定谁正在访问网站。一般需要在爬虫请求头中设置User-Agent(有的网站可能需要确定Accept、Cookie、Referer、Host等,根据具体情况设置)将爬虫伪装成普通浏览器用户并防止其被反爬虫机制拦截。 Request Payload:请求参数,服务器会根据这些参数决定返回给你哪些数据,比如页码,关键词等,找到这些参数的规则,你可以通过构造这些参数数据。 1.1.3 服务器返回的数据有哪些形式
一般情况下有两种格式,html和json。接下来我就简单教大家如何判断。
HTML 格式
一般情况下,它会出现在过滤条件中的Doc类型中,也很容易区分。它在响应中查看。整篇文章都打上了这种标签。
如果你确定html源码中收录了你需要的数据(所以,因为有些情况下数据是通过js代码动态加载的,直接解析源码是找不到数据的)
在Elements中,你可以通过左上角的箭头按钮,快速方便的定位到网页上数据所在的标签(我就不赘述了,自己试试就明白了) .
大多数人从解析html开始学习爬虫,所以应该对它比较熟悉。解析方法很多,比如正则表达式、BeautifulSoup、xpath等。
Json 格式
如前所述,在某些情况下,数据不是直接在html页面返回,而是通过其他数据接口动态请求加载。这就导致了一些同学刚开始学习爬虫的时候,在网页上分析的时候,标签路径是可以的,但是请求代码的时候却找不到标签。
这种动态加载数据的机制叫做Ajax,有兴趣的可以自行搜索。
ajax请求在请求类型上一般都是XHR,数据内容一般以json格式显示。 (有同学不知道怎么判断一个请求是ajax还是数据是不是json,我该怎么做呢?这里有一个简单的判断方法。在Preview中看看是不是类似下面的表格,大括号, 键值对 { "xxx": "xxx"}, 一个可以开闭的小三角形)
这种类型的请求返回的数据是json格式的,可以直接用python中的json库解析,非常方便。
上面给大家简单介绍了如何分析网页,如何抓包。希望对大家有帮助。
贴上正题,通过上面介绍的方法,我们不难知道人民网的搜索结果数据是通过Ajax发送的。
请求方法是POST。请求链接、请求头、请求参数都可以在Headers中查看。
在参数中,我们可以看到key应该是我们搜索到的关键词,page是页码,sortType是搜索结果的排序方式等等,知道这些规则,所以我们可以自己构造请求。
1.2 探索防爬机制
一般网站会设置一些防爬机制来防止攻击。下面简单介绍一些常见的防爬机制及对策。
1.2.1 用户代理
服务器会根据请求头中的User-Agent字段判断用户访问什么,如:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.146 Safari/537.36
此处收录有关浏览器和计算机系统的一些基本信息。如果你的python爬虫代码没有设置这个字段值,会默认为python,这样服务器就可以大致判断请求是爬虫发起的,然后选择是否拦截。
解决方法也比较简单,就是用浏览器访问时,复制请求头中的User-Agent值,在代码中设置。
1.2.2 推荐人
一些网站 资源添加了反水蛭链接。也就是说,服务器在处理请求的时候,会判断Referer的值。只有在指定站点发起请求时,服务器才会允许返回数据(这样可以防止资源被其他网站盗用和使用)。
响应方式也很简单,浏览器访问时复制请求头中的Referer值即可。
1.2.3 饼干
有些网站可能需要登录账号才能访问一些数据,此处使用cookie值。
如果不设置cookie,可以设置未登录时访问的cookie,登录账号后设置cookie。数据结果可能不同。
响应方式因网站而异。如果您无需设置 cookie 即可访问,那么请不要在意;如果需要设置访问,则根据情况(是否要登录,是否要成为会员等)复制浏览器请求header中的cookie值进行设置。
1.2.4 JS参数加密
在请求参数中,可能会有一些类似乱码的参数。你不知道它是什么,但它非常重要。它不是时间戳。不填写或随便填写,都会导致请求失败。
这种情况比较困难。这是js算法加密后的参数。如果要自己构建,则需要模拟整个参数加密算法。
但是由于这个加密过程是由前端完成的,所以完全可以得到加密算法的js代码。如果你了解一些前端知识,或者逆向Js,可以尝试破解。
我个人不推荐这个。一是破解麻烦,二是可能违法。
或者,使用 selenium 或 ``pyppeteer` 自动抓取。不香。
1.2.5 抓取频率限制
数据如果长时间频繁爬取,网站服务器的压力会很大,普通人不可能访问这么高强度的访问(比如每次十几次)第二个网站) 乍一看,爬虫做到了。因此,服务器通常会设置访问频率阈值。例如,如果一分钟内发起的请求超过300个,则视为爬虫,限制访问其IP。
响应,我建议如果你不是特别着急,可以设置一个延迟功能,每次抓取数据时随机休眠几秒,让访问频率降低到阈值以下,并且降低服务器访问压力。减少 IP 阻塞的机会。
1.2.6 其他
有一些不太常见但也更有趣的防攀爬机制。让我给你举几个例子。
以上是一些常见的防爬机制,希望对大家有帮助。
经过测试,人民网的防爬机制并不是特别严格。如果参数设置正确,抓取基本不会受到限制。
但如果是数据量比较大的爬取,最好设置爬取延迟和断点连续爬取功能。
1.3 改进代码
首先导入所需的库。
本爬虫代码中各个库的用处已在评论中标明。
import requests # 发起网络请求
from bs4 import BeautifulSoup # 解析HTML文本
import pandas as pd # 处理数据
import os
import time # 处理时间戳
import json # 用来解析json文本
发起网络请求函数fetchUrl
代码注释中已经标注了函数的用途和三个参数的含义,返回值为json类型数据
'''
用于发起网络请求
url : Request Url
kw : Keyword
page: Page number
'''
def fetchUrl(url, kw, page):
# 请求头
headers={
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/json;charset=UTF-8",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36",
}
# 请求参数
payloads = {
"endTime": 0,
"hasContent": True,
"hasTitle": True,
"isFuzzy": True,
"key": kw,
"limit": 10,
"page": page,
"sortType": 2,
"startTime": 0,
"type": 0,
}
# 发起 post 请求
r = requests.post(url, headers=headers, data=json.dumps(payloads))
return r.json()
数据分析函数parseJson
解析json对象,然后将解析后的数据包装成数组返回
def parseJson(jsonObj):
#解析数据
records = jsonObj["data"]["records"];
for item in records:
# 这里示例解析了几条,其他数据项如末尾所示,有需要自行解析
pid = item["id"]
originalName = item["originalName"]
belongsName = item["belongsName"]
content = BeautifulSoup(item["content"], "html.parser").text
displayTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(item["displayTime"]/1000))
subtitle = item["subtitle"]
title = BeautifulSoup(item["title"], "html.parser").text
url = item["url"]
yield [[pid, title, subtitle, displayTime, originalName, belongsName, content, url]]
数据保存功能saveFile
'''
用于将数据保存成 csv 格式的文件(以追加的模式)
path : 保存的路径,若文件夹不存在,则自动创建
filename: 保存的文件名
data : 保存的数据内容
'''
def saveFile(path, filename, data):
# 如果路径不存在,就创建路径
if not os.path.exists(path):
os.makedirs(path)
# 保存数据
dataframe = pd.DataFrame(data)
dataframe.to_csv(path + filename + ".csv", encoding='utf_8_sig', mode='a', index=False, sep=',', header=False )
主要功能
if __name__ == "__main__":
# 起始页,终止页,关键词设置
start = 1
end = 3
kw = "春节"
# 保存表头行
headline = [["文章id", "标题", "副标题", "发表时间", "来源", "版面", "摘要", "链接"]]
saveFile("./data/", kw, headline)
#爬取数据
for page in range(start, end + 1):
url = "http://search.people.cn/api-search/elasticSearch/search"
html = fetchUrl(url, kw, page)
for data in parseJson(html):
saveFile("./data/", kw, data)
print("第{}页爬取完成".format(page))
# 爬虫完成提示信息
print("爬虫执行完毕!数据已保存至以下路径中,请查看!")
print(os.getcwd(), "\\data")
以上就是这个爬虫的全部代码。您可以在此基础上对其进行修改和使用。仅供学习交流使用,请勿用于非法用途。
注:文字爬取的代码这里就不写了。一个是人脉文章mato爬取的功能在上一篇文章已经写好了。如果需要,可以自行集成代码;另一个是,抓取文本会引入一些其他问题,例如链接失败,文章来自不同的网站,以及不同的解析方法。这是一个很长的故事。本文主要讲思路。
1.4 成就展示1.4.1 程序运行效果
1.4.2 爬坡数据展示
2. 使用现有数据进行过滤
如果你提前下载了所有的新闻文章data,那么这个方法无疑是最方便的,省去了爬取数据的漫长过程,也让你免于对抗反爬机制。
2.1 数据源
下载链接:
以上是一位读者朋友爬取的人民日报新闻数据,包括19年至今的数据。每月更新一次,应该可以满足大量人的数据需求。
另外,我还有之前爬过的整整18年的数据。有需要的朋友可以私聊我。
2.2 搜索代码
以下图所示的目录结构为例。
假设我们有一些关键词,需要检查文章这些消息中哪些收录关键词。
import os
# 这里是你文件的根目录
path = "D:\\Newpaper\\2018"
# 遍历path路径下的所有文件(包括子文件夹下的文件)
def iterFilename(path):
#将os.walk在元素中提取的值,分别放到root(根目录),dirs(目录名),files(文件名)中。
for root, dirs, files in os.walk(path):
for file in files:
# 根目录与文件名组合,形成绝对路径。
yield os.path.join(root,file)
# 检查文件中是否包含关键词,若包含返回True, 若不包含返回False
def checkKeyword(filename, kwList):
with open(filename, "r", encoding="utf-8") as f:
content = f.read()
for kw in kwList:
if kw in content:
return True, kw
return False, ""
if __name__ == "__main__":
# 关键词数组
kwList = ["经济", "贸易"]
#遍历文章
for file in iterFilename(path):
res, kw = checkKeyword(file, kwList)
if res:
# 如果包含关键词,打印文件名和匹配到的关键词
print("文件 ", file," 中包含关键词 ", kw)
2.3 运行结果
运行程序从文件中过滤掉收录关键词的文章。
如果文章不清楚,或者解释有误,请在评论区批评指正,或扫描下方二维码加我微信。让我们一起学习交流,共同进步。