根据关键词文章采集系统(《人民日报》爬虫文章反馈:遍历文件夹将搜索结果爬取下来即可 )
优采云 发布时间: 2021-10-16 11:27根据关键词文章采集系统(《人民日报》爬虫文章反馈:遍历文件夹将搜索结果爬取下来即可
)
上一篇《人民日报》的爬虫文章发布了,收到了很好的反馈。文章中的爬虫代码确实帮助了很多人。我很高兴。
在和读者交流的过程中,我也发现了一些共同的需求,就是根据关键词文章过滤新闻。
我最初的想法是在爬取所有文章数据的基础上遍历文件夹,然后过滤掉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()要与此一致,否则可能无法正确获取数据。Request Headers:请求头,服务器会根据这个判断谁在访问网站。一般需要在爬虫请求头中设置User-Agent(有些网站可能需要判断Accept、Cookie、Referer、Host等,根据具体情况设置)来伪装爬虫普通浏览器用户,防止被反爬虫机制拦截。请求负载:请求参数。服务器会根据这些参数决定返回给你哪些数据,比如页码,关键词等,找到这些参数的规则,你可以直接构造这些参数给服务器获取数据。1.1.3 服务器返回的数据有哪些形式?
一般情况下有两种格式,html和json。下面我就简单教大家如何判断。
HTML格式
一般情况下,它会出现在过滤条件中的Doc类型中,也很容易区分。在Response中查看,整篇文章都有这种标签。
如果你确定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.关键词1@>1 个用户代理
服务器将使用请求头中的 User-Agent 字段来确定用户正在通过什么访问,例如:
关键词2@>
这里收录有关浏览器和计算机系统的一些基本信息。如果你的python爬虫代码没有设置这个字段值,会默认为python,这样服务器就可以大致判断请求是爬虫发起的,然后选择是否拦截。
解决方法也比较简单,就是用浏览器访问的时候,复制请求头中的User-Agent值,在代码中设置。
1.关键词1@>2 Referer
一些 网站 资源添加了反水蛭链接。也就是说,服务器在处理请求的时候,会判断Referer的值。只有在指定站点发起请求时,服务器才会允许返回数据(这样可以防止资源被其他网站使用)。
响应的方法也很简单,浏览器访问时复制请求头中的Referer值即可。
1.关键词1@>3 饼干
对于一些网站,可能需要登录一些数据才能访问,这里使用的是cookie值。
如果不设置cookies,设置未登录时访问的cookies,登录账号后设置cookies,数据结果可能会有所不同。
响应方式因网站而异。如果你不用设置cookies就可以访问,那就不要在意;如果需要设置访问,则根据情况(是否要登录,是否要成为会员等)复制浏览器请求头中的cookie值来设置。
1.关键词1@>4 JS参数加密
在请求参数中,可能会有一些类似乱码的参数。你不知道它是什么,但它非常重要。它不是时间戳。如果不填写或随便填写,都会导致请求失败。
这种情况比较难处理。这是js算法加密后的参数。如果要自己构建,则需要模拟整个参数加密算法。
不过由于这个加密过程是由前端完成的,所以完全可以得到加密算法的js代码。如果你了解一些前端知识,或者Js反了,可以尝试破解。
我个人不推荐这个。一是破解麻烦,二是可能违法。
换句话说,使用 selenium 或 ``pyppeteer` 自动抓取。它不香。
1.关键词1@>5 爬行频率限制
如果数据长时间爬取频繁,网站的服务器压力非常大,普通人无法访问到如此高强度的访问(比如每秒十几次访问网站),爬虫第一眼就做到了。因此,服务器通常会设置访问频率阈值。例如,如果它在一分钟内发起超过300个请求,则视为爬虫,其IP被限制访问。
对此,我建议如果你不是特别着急的话,可以设置一个延时功能,每次爬取数据时随机休眠几秒,让访问频率降低到阈值以下,减少压力服务器访问,并减少 IP 阻塞。几率。
1.关键词1@>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")
以上就是这个爬虫的全部代码。您可以在此基础上对其进行修改和使用。仅供学习交流使用,不得用于非法用途。
注意:这里不写文字爬取的代码。一、人民网文章的文字爬取功能在上一篇文章中已经写过。如果需要,可以自行集成代码;二是,爬取文本会引入一些其他的问题,比如链接失败、文章来自不同的网站、不同的解析方式等等,这就说来话长了。这篇文章主要集中在思想上。
1.4 成果展示1.4.1 程序运行效果
1.4.2 爬坡数据显示
关键词1@> 使用现有数据进行过滤
如果你已经提前下载了所有的新闻文章数据,那么这种方式无疑是最方便的,省去了爬取数据的漫长过程,也让你免于对抗反爬机制。
关键词1@>1 数据源
下载链接:
以上是一位读者朋友爬取的人民日报新闻数据,包括19年至今的数据。每月更新一次,应该可以满足海量人群对数据的需求。
另外,我还有前18年的数据。有需要的朋友可以私聊我。
关键词1@>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)
关键词1@>3 运行结果
运行程序,从文件中过滤掉收录关键词的文章。
2021 年 9 月 9 日更新
近日,有读者在转载文章中的爬虫时,发现如下错误:
在 parseJson 记录 = jsonObj[“数据”][“记录”];
类型错误:“数据”
经过调试检查,发现报这个错误是因为改变了原来网站中关键词搜索的接口,导致数据采集失败。
解决方案:
只需将主要功能部分的url替换为新的界面即可,如下图。
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"
url = "http://search.people.cn/api-search/front/search"
html = fetchUrl(url, kw, page)
for data in parseJson(html):
saveFile("./data/", kw, data)
print("第{}页爬取完成".format(page))
# 爬虫完成提示信息
print("爬虫执行完毕!数据已保存至以下路径中,请查看!")
print(os.getcwd(), "\\data")
如果文章有什么不明白的地方,或者解释有误,欢迎在评论区批评指正,或扫描下方二维码加我微信。让我们一起学习交流,共同进步。