querylist采集微信公眾號文章(如何爬取公眾號所有文章(一)(1)_光明網(wǎng)(組圖))
優(yōu)采云 發(fā)布時(shí)間: 2022-01-22 11:06querylist采集微信公眾號文章(如何爬取公眾號所有文章(一)(1)_光明網(wǎng)(組圖))
文章目錄
一、前言
前幾天書(shū)文問(wèn)我能不能爬取微信公眾號“北京郵教部”的歷史動(dòng)態(tài),分析最多的成績(jì)和科目。之前沒(méi)做過(guò)微信公眾號爬蟲(chóng),所以研究了一下,發(fā)現了這個(gè)文章。
二、準備三、正式開(kāi)始(一)批量獲取之前公眾號推送的url鏈接1.在后臺插入其他公眾號推送超鏈接的原理微信公眾號
如果要批量抓取微信公眾號過(guò)去的推送,最大的問(wèn)題是如何獲取這些推送的url鏈接。因為通常我們點(diǎn)擊一??個(gè)推送時(shí),微信會(huì )隨機生成一個(gè)url鏈接,而這個(gè)隨機生成的url與公眾號推送的其他url沒(méi)有任何關(guān)聯(lián)。因此,如果我們要批量抓取公眾號的所有推送,需要手動(dòng)點(diǎn)擊每條推送,復制每條推送的url鏈接。這顯然是不現實(shí)的。在廣泛查閱各種資料后,我學(xué)會(huì )了如何爬取公眾號所有文章this文章的方法。
這種方式的原理是,當我們登錄微信公眾號后臺編輯圖文素材時(shí),可以在素材中插入其他公眾號的推送鏈接。這里,微信公眾號后臺會(huì )自動(dòng)調用相關(guān)API,返回公眾號推送的所有長(cháng)鏈接列表。
我們打開(kāi)Chrome瀏覽器的查看模式,選擇網(wǎng)絡(luò ),然后在編輯超鏈接界面的公眾號搜索欄中輸入“北京郵政家教部”,搜索并選擇公眾號,發(fā)現已經(jīng)刷新了一個(gè)網(wǎng)絡(luò )啟動(dòng)以“appmsg”開(kāi)頭的內容,這是我們分析的目標。
我們點(diǎn)擊“appmsg”開(kāi)頭的內容,解析請求的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
鏈接分為三個(gè)部分:
request的基本部分?action=list_ex常用于動(dòng)態(tài)網(wǎng)站,實(shí)現不同的參數值生成不同的頁(yè)面或返回不同的結果&begin=0&count=5&fakeid=MjM5NDY3ODI4OA==&type=9&query=&token= 1983840068&lang=zh_CN&f =json&ajax=1 設置各種參數2.獲取Cookie和User-Agent
如果使用Python的Requests庫直接訪(fǎng)問(wèn)url,是無(wú)法正常獲取結果的。原因是在使用網(wǎng)頁(yè)版微信公眾號在后臺插入超鏈接時(shí),我們處于登錄狀態(tài),但是當我們使用python直接訪(fǎng)問(wèn)時(shí),我們并沒(méi)有處于登錄狀態(tài)。因此,我們需要在訪(fǎng)問(wèn)時(shí)手動(dòng)獲取Cookie和User-Agent,并在使用Python的Requests庫訪(fǎng)問(wèn)時(shí)將它們傳遞到headers參數中。這里說(shuō)一下,我把公眾號標識符 fakeid 和 token 參數保存在一個(gè) yaml 文件中,方便爬取時(shí)加載。
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 是當前請求的頁(yè)數。當begin設置為0時(shí),會(huì )以json格式返回最近五次推送信息,以此類(lèi)推。
4.開(kāi)始爬取
通過(guò)一個(gè)循環(huán),begin的值每次加1,循環(huán)爬?。?/p>
i = 0
while True:
begin = i * 5
params["begin"] = str(begin)
# 隨機暫停幾秒,避免過(guò)快的請求導致過(guò)快的被查到
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}頁(yè)爬取成功\n")
print("\n".join(info.split(",")))
print("\n\n---------------------------------------------------------------------------------\n")
# 翻頁(yè)
i += 1
在爬取大約 50 個(gè)頁(yè)面時(shí),我遇到了以下錯誤:
{'base_resp':{'err_msg':'頻率控制','ret':200013}}
這是因為微信公眾號有流量限制,所以你可以等一個(gè)小時(shí)。我在這里使用以下代碼來(lái)解決它:
# 微信流量控制
if resp.json()['base_resp']['ret'] == 200013:
print("frequencey control, stop at {}".format(str(begin)))
time.sleep(3600)
continue
對于每條爬取的信息,對其進(jìn)行解析并將其存儲在一個(gè) 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語(yǔ)句
# 也方便重新運行時(shí)設置頁(yè)數
with open("app_msg_list.csv", "w",encoding='utf-8') as file:
file.write("文章標識符aid,標題title,鏈接url,時(shí)間time\n")
i = 0
while True:
begin = i * 5
params["begin"] = str(begin)
# 隨機暫停幾秒,避免過(guò)快的請求導致過(guò)快的被查到
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}頁(yè)爬取成功\n")
print("\n".join(info.split(",")))
print("\n\n---------------------------------------------------------------------------------\n")
# 翻頁(yè)
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.提取信息并寫(xiě)入文件
我們需要提取的是每個(gè)導師信息的年級和科目。通過(guò)觀(guān)察推送結構,我決定使用正則表達式進(jìn)行提取。
有的家教訂單長(cháng)時(shí)間沒(méi)有回復,會(huì )在多個(gè)帖子中重復出現,從而影響我們的統計結果。我決定用數字來(lái)識別不同的輔導信息,相同的數字只會(huì )計算一次。所以使用下面的正則表達式來(lái)匹配:
<p>re_project = re.compile(r">編號(.*?)年級(.*?)科目(.*?)科目(.*?)年級(.*?)編號(.*?)年級(.*?)科目(.*?)