querylist采集微信公众号文章(批量获取公众号推送超链接的原理(图)介绍)
优采云 发布时间: 2022-01-17 22:08querylist采集微信公众号文章(批量获取公众号推送超链接的原理(图)介绍)
一、前言
二、准备
三、正式开始
四、结束语
一、前言
前几天书文问我能不能爬取微信公众号“北京邮教部”的历史动态,分析最多的成绩和科目。之前没做过微信公众号爬虫,所以研究了一下,发现了这个文章。
二、准备三、正式开始(一)批量获取之前公众号推送的url链接1.微信后台插入其他公众号推送超链接的原理公众号
如果要批量抓取微信公众号过去的推送,最大的问题是如何获取这些推送的url链接。因为通常我们点击一个推送时,微信会随机生成一个url链接,而这个随机生成的url与公众号推送的其他url没有任何关联。因此,如果我们要批量抓取公众号的所有推送,需要手动点击每条推送,复制每条推送的url链接。这显然是不现实的。在广泛查阅各种资料后,我学会了如何爬取公众号所有文章this文章的方法。
这种方式的原理是,当我们登录微信公众号后台编辑图文素材时,可以在素材中插入其他公众号的推送链接。这里,微信公众号后台会自动调用相关API,返回公众号推送的所有长链接列表。
我们打开Chrome浏览器的查看模式,选择网络,然后在编辑超链接界面的公众号搜索栏中输入“北京邮政家教部”,搜索并选择公众号,发现一个刷新的网络以“开头” appmsg”开头的内容,这是我们分析的目标。
我们点击“appmsg”开头的内容,解析请求的url:
https://mp.weixin.qq.com/cgi-bin/appmsg?action=list_ex&begin=0&count=5&fakeid=MjM5NDY3ODI4OA==&type=9&query=&token=1983840068&lang=zh_CN&f=json&ajax=1
链接分为三个部分:
request的基本部分?action=list_ex常用于动态网站,实现不同的参数值生成不同的页面或返回不同的结果&begin=0&count=5&fakeid=MjM5NDY3ODI4OA==&type=9&query=&token= 1983840068&lang=zh_CN&f =json&ajax=1 设置各种参数2.获取Cookie和User-Agent
如果使用Python的Requests库直接访问url,是无法正常获取结果的。原因是在使用网页版微信公众号在后台插入超链接时,我们处于登录状态,但是当我们使用python直接访问时,我们并没有处于登录状态。因此,我们需要在访问时手动获取Cookie和User-Agent,并在使用Python的Requests库访问时将它们传递到headers参数中。这里说一下,我把公众号标识符 fakeid 和 token 参数保存在一个 yaml 文件中,方便爬取时加载。
cookie : appmsglist_action_3899……
user_agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64)……
fakeid : MzI4M……
token : "19……
在python代码中加载如下:
import yaml
with open("wechat.yaml", "r") as file:
file_data = file.read()
config = yaml.safe_load(file_data)
headers = {
"Cookie": config['cookie'],
"User-Agent": config['user_agent']
}
3.设置url参数
然后我们设置要请求的url链接的参数:
# 请求参数
url = "https://mp.weixin.qq.com/cgi-bin/appmsg"
begin = "0"
params = {
"action": "list_ex",
"begin": begin,
"count": "5",
"fakeid": config['fakeid'],
"type": "9",
"token": config['token'],
"lang": "zh_CN",
"f": "json",
"ajax": "1"
}
这里,count 是请求返回的信息数,begin 是当前请求的页数。当begin设置为0时,会以json格式返回最近五次推送信息,以此类推。
4.开始爬取
通过一个循环,begin的值每次加1,循环爬取:
i = 0
while True:
begin = i * 5
params["begin"] = str(begin)
# 随机暂停几秒,避免过快的请求导致过快的被查到
time.sleep(random.randint(1,10))
resp = requests.get(url, headers=headers, params = params, verify=False)
# 微信流量控制, 退出
if resp.json()['base_resp']['ret'] == 200013:
print("frequencey control, stop at {}".format(str(begin)))
time.sleep(3600)
continue
# 如果返回的内容中为空则结束
if len(resp.json()['app_msg_list']) == 0:
print("all ariticle parsed")
break
msg = resp.json()
if "app_msg_list" in msg:
for item in msg["app_msg_list"]:
info = '"{}","{}","{}","{}"'.format(str(item["aid"]), item['title'], item['link'], str(item['create_time']))
with open("app_msg_list.csv", "a",encoding='utf-8') as f:
f.write(info+'\n')
print(f"第{i}页爬取成功\n")
print("\n".join(info.split(",")))
print("\n\n---------------------------------------------------------------------------------\n")
# 翻页
i += 1
爬了大概50页的时候,遇到如下错误:{'base_resp': {'err_msg': 'freq control', 'ret': 200013}}这是因为微信公众号有流量限制,等一个小时就好了. 我在这里使用以下代码来解决它:
# 微信流量控制
if resp.json()['base_resp']['ret'] == 200013:
print("frequencey control, stop at {}".format(str(begin)))
time.sleep(3600)
continue
对于每条爬取的信息,对其进行解析并将其存储在一个 csv 文件中:
msg = resp.json()
if "app_msg_list" in msg:
for item in msg["app_msg_list"]:
info = '"{}","{}","{}","{}"'.format(str(item["aid"]), item['title'], item['link'], str(item['create_time']))
with open("python小屋.csv", "a",encoding='utf-8') as f:
f.write(info+'\n')
5.完整代码
完整代码如下:
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : Spider.py
@Time : 2021/06/04 02:20:24
@Author : YuFanWenShu
@Contact : 1365240381@qq.com
'''
# here put the import lib
import json
import requests
import time
import random
import yaml
with open("wechat.yaml", "r") as file:
file_data = file.read()
config = yaml.safe_load(file_data)
headers = {
"Cookie": config['cookie'],
"User-Agent": config['user_agent']
}
# 请求参数
url = "https://mp.weixin.qq.com/cgi-bin/appmsg"
begin = "0"
params = {
"action": "list_ex",
"begin": begin,
"count": "5",
"fakeid": config['fakeid'],
"type": "9",
"token": config['token'],
"lang": "zh_CN",
"f": "json",
"ajax": "1"
}
# 存放结果
app_msg_list = []
# 在不知道公众号有多少文章的情况下,使用while语句
# 也方便重新运行时设置页数
with open("app_msg_list.csv", "w",encoding='utf-8') as file:
file.write("文章标识符aid,标题title,链接url,时间time\n")
i = 0
while True:
begin = i * 5
params["begin"] = str(begin)
# 随机暂停几秒,避免过快的请求导致过快的被查到
time.sleep(random.randint(1,10))
resp = requests.get(url, headers=headers, params = params, verify=False)
# 微信流量控制, 退出
if resp.json()['base_resp']['ret'] == 200013:
print("frequencey control, stop at {}".format(str(begin)))
time.sleep(3600)
continue
# 如果返回的内容中为空则结束
if len(resp.json()['app_msg_list']) == 0:
print("all ariticle parsed")
break
msg = resp.json()
if "app_msg_list" in msg:
for item in msg["app_msg_list"]:
info = '"{}","{}","{}","{}"'.format(str(item["aid"]), item['title'], item['link'], str(item['create_time']))
with open("app_msg_list.csv", "a",encoding='utf-8') as f:
f.write(info+'\n')
print(f"第{i}页爬取成功\n")
print("\n".join(info.split(",")))
print("\n\n---------------------------------------------------------------------------------\n")
# 翻页
i += 1
6.爬取结果
最终结果保存在 csv 文件中,一共 565 条推送消息:
(二)对每次推送进行爬取,提取需要的信息1.对每次推送进行遍历和爬取
从 csv 文件中读取每次推送的 url 链接,并使用 Requests 库抓取每次推送的内容:
with open("app_msg_list.csv","r",encoding="utf-8") as f:
data = f.readlines()
n = len(data)
for i in range(n):
mes = data[i].strip("\n").split(",")
if len(mes)!=4:
continue
title,url = mes[1:3]
if i>0:
r = requests.get(eval(url),headers=headers)
if r.status_code == 200:
text = r.text
projects = re_project.finditer(text)
2.提取信息并写入文件
我们需要提取的是每个导师信息的年级和科目。通过观察推送结构,我决定使用正则表达式进行提取。
有的家教订单长时间没有回复,会在多个帖子中重复出现,从而影响我们的统计结果。我决定用数字来识别不同的辅导信息,相同的数字只会计算一次。所以使用下面的正则表达式来匹配:
<p>re_project = re.compile(r">编号(.*?)年级(.*?)科目(.*?)科目(.*?)年级(.*?)编号(.*?)年级(.*?)科目(.*?)