前言

前几天研究人民网新闻排行榜时发现了一篇文章,当时感觉讲的内容挺多没细看,今天再翻出来感觉讲的特别详细,对于新手的我真是受益匪浅,也解答了我的很多疑惑,主要是爬取网页的json信息,各种头信息的用处,反爬机制和应对办法等等。附链接:(133条消息) Python爬虫实战 | 人民网爬虫 根据关键词筛选新闻文章亮出锋芒,剑指苍穹-CSDN博客人民网爬虫

思路及实践

在搜索界面进行搜索,得到的页面源码中找不到所需信息,在调试—网络中的文件发现所需信息

获取json源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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, likeGecko) Chrome / 92.0.4515.107Safari / 537.36Edg / 92.0.902.55",
"Referer": "http://search.people.cn/", #访问来源
"Cookie": "__jsluid_h = 42549df2735923361d7d5862a7faf64f;sso_c = 0;sfr = 1",
}

# 请求参数
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()

各项参数均可以在调试中的头部文件中找到,注意Referer必须要填写,否则会被服务器识别为黑客攻击,无法获取源码

Request URL:也就是请求的链接。爬虫请求的 url 填啥是要看这里,不要只知道去浏览器的地址栏里复制网址。
Request Method:请求方法,有 GET 和 POST 两种,爬虫代码里用 requests.get() 还是 requests.post() 要与这里保持一致,否则可能无法正确获取数据。
Request Headers:请求头,服务器会根据这个来判断是谁在访问网站,一般情况下,你需要设置爬虫请求头中的 User-Agent (有的网站可能需要判断 Accept ,Cookie ,Referer,Host 等,根据具体情况设置),来将爬虫伪装成正常的浏览器用户,防止被反爬机制拦截。
Request Payload:请求参数,服务器会根据这些参数,来确定返回哪些数据给你,比如说,页码,关键词,等等,找到这些参数的规律,就可以通过构造这些参数,来直接向服务器获取数据了。

解析json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def parseJson(jsonObj):
# 解析数据
records = jsonObj["data"]["records"];
for item in records:
# 这里示例解析了几条,其他数据项如末尾所示,有需要自行解析
pid = item["id"]
belongsName = item["belongsName"]
content = BeautifulSoup(item["content"], "html.parser").text
displayTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(item["displayTime"] / 1000)) #未处理数据样式:1641429799000
title = BeautifulSoup(item["title"], "html.parser").text
url = item["url"]
yield [[pid, title, displayTime, belongsName, content, url]]

# datalist.append([[pid, title, displayTime, belongsName, content, url]]) #上面yield函数可等效于此代码(datalist需要先声明)
# return datalist

以上各种参数可在调试界面中找到,本例中原数据:

点击展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{author: "本报记者 汪文正", belongsName: "#滚动新闻#社会#陕西频道#", belongsId: "["337341","378296","186331"]",…}
author: "本报记者 汪文正"
belongsId: "[\"337341\",\"378296\",\"186331\"]"
belongsName: "#滚动新闻#社会#陕西频道#"
content: "岁末年初,多家快递企业宣布2022年“<em>春节</em>不打烊”,满足春节期间的快递寄递需求。对消费者特别是广大“就地过年”群体而言,这无疑是一个好消息。也有人好奇,快递服务<em>春节</em>不停转,相关承诺如何落实?近期,多家快递公司明确,2022年<em>春节</em>“不打烊”以满足节日期间消费者寄递需求。2021年12月14日,德邦快递率先宣布“<em>春节</em>不休”,为年货等物资顺畅流通提供快递服务。服务质量不降低 尽管部分快递企业宣布“<em>春节</em>不打烊”,但随着<em>春节</em>临近和部分网点快递员提前返乡,不少消费者担心快递服务质量下滑。 “最近快递在路上消耗的时间更长了。杨达卿分析,随着中国劳动力红利退潮及一线城市生活成本提高,满足“<em>春节</em>不打烊”用工需求面临一定挑战。不过,“<em>春节</em>不打烊”并不代表一定要全员留守,否则也会造成资源浪费。中通快递表示,会为<em>春节</em>留守的一线员工提供完善的激励政策和福利保障,以保证快递小哥就地快乐过年和服务质量稳定;极兔速递也提出,将为<em>春节</em>留守员工提供福利保障。"
contentId: 35083522
displayTime: 1641429799000
domain: null
editor: "麦文雄 "
hasImg: 0
hasVideo: 0
id: 2000035083522
imageUrl: null
inputTime: 1641429799000
isDisclosed: null
isElited: null
isFixed: null
isOfficial: null
isRecommend: null
keyword: ""
newsJson: null
originNodeRname: null
originUrl: "http://paper.people.com.cn/rmrbhwb/html/2022-01/06/content_25897034.htm "
originalName: null
originalType: null
pretitle: "近期多家快递企业宣布2022年春节不休,为年货等物资流通提供服务——"
shorttitle: ""
source: 2
sourceId: 35083522
sourceType: 1
sourcetitle: "今年春节,快递不打烊!"
subtitle: ""
title: "今年<em>春节</em>,快递不打烊!"
url: "http://sn.people.com.cn/n2/2022/0106/c186331-35083522.html"

效果图

附源代码

点击展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import requests						# 发起网络请求
from bs4 import BeautifulSoup # 解析HTML文本
import pandas as pd # 处理数据
import os
import time # 处理时间戳
import json # 用来解析json文本


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, likeGecko) Chrome / 92.0.4515.107Safari / 537.36Edg / 92.0.902.55",
"Referer": "http://search.people.cn/", #访问来源
"Cookie": "__jsluid_h = 42549df2735923361d7d5862a7faf64f;sso_c = 0;sfr = 1",
}

# 请求参数
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()


def parseJson(jsonObj):
# 解析数据
records = jsonObj["data"]["records"];
for item in records:
# 这里示例解析了几条,其他数据项如末尾所示,有需要自行解析
pid = item["id"]
belongsName = item["belongsName"]
content = BeautifulSoup(item["content"], "html.parser").text
displayTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(item["displayTime"] / 1000)) #未处理数据样式:1641429799000
title = BeautifulSoup(item["title"], "html.parser").text
url = item["url"]
yield [[pid, title, displayTime, belongsName, content, url]]

# datalist.append([[pid, title, displayTime, belongsName, content, url]]) #上面yield函数可等效于此代码(datalist需要先声明)
# return datalist


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/search-platform/front/search"
html = fetchUrl(url, kw, page)
# data = parseJson(html)
# for item in data:
# print(item) 每个item都储存了一个新闻的信息,如[1000032325931, '广西柳州:螺蛳粉企业备战春节市场', '2022-01-07 08:43:00', '#文旅·体育#', '离春节还有不到一个月时间,广西柳州市各大螺蛳粉企业积极生产,全力供应节前市场。 \u3000\u3000离春节还有不到一个月时间,广西柳州市各大螺蛳粉企业积极生产,全力供应节前市场。 \u3000\u3000新华社记者 黄孝邦 摄', 'http://finance.people.com.cn/n1/2022/0107/c1004-32325931.html']
for data in parseJson(html):
saveFile("./data/", kw, data)
print("第{}页爬取完成".format(page))

# 爬虫完成提示信息
print("爬虫执行完毕!数据已保存至以下路径中,请查看!")
print(os.getcwd(), "\\data")