一个好的公众号爬虫将内容抓取保存下来慢慢赏析

优采云 发布时间: 2021-08-15 19:09

  一个好的公众号爬虫将内容抓取保存下来慢慢赏析

  有时候我们会遇到一个很好的公众号,里面的每一篇文章都值得反复阅读。这时候我们就可以使用公众号爬虫抓取并保存内容,慢慢欣赏。

  安装 Fiddler

  Fiddler的下载地址为:安装完成后,确保手机和电脑的网络是同一个局域网。

  Finder 配置

  点击工具>>选项>>连接面板,参考下图配置,Fiddler的默认端口是8888,如果8888端口被占用,可以修改为其他端口。

  点击工具>>选项>>HTTPS面板,参考下图进行配置

  安卓手机配置

  进入WLAN设置,选择当前局域网的WIFI设置,代理设置为手动,代理服务器主机名为Finder,右上角点击在线,端口号为8888。

  在手机浏览器中访问配置的地址:8888,显示Fiddler Echo Service时,手机配置成功。

  为了让 Finddler 拦截 HTTPS 请求,必须在手机中安装 CA 证书。在 :8888 中,单击 FiddlerRoot 证书下载并安装证书。至此配置工作完成。

  微信历史页面

  以【腾旭大神网】为例,点击【上海新闻】菜单的二级菜单【历史新闻】。

  观察 Fiddler 的变化。此时,左侧窗口中会陆续出现多个URL连接地址。这是 Fiddler 截获的 Android 请求。

  Result:服务器的响应结果 Protocol:请求协议,微信协议都是HTTPS,所以需要在手机和PC端安装证书。 HOST: 主机名 URL: URL 地址

  以 .com/mp/profile_ext?action=home... 开头的 URL 之一正是我们所需要的。点击右侧的Inspectors面板,然后点击下方的Headers和WebView面板,会出现如下图案

  标题面板

  Request Headers:请求行,收录请求方法、请求地址、等待C​​lient的请求协议、Cookies:请求头

  WebView 面板

  WebView面板显示服务器返回的HTML代码的渲染结果,Textview面板显示服务器返回的HTML源代码

  获取历史页面

  在上一节中,公众号消息历史页面已经可以在 Fiddler 的 WebView 面板中显示。本节使用Python抓取历史页面。创建一个名为wxcrawler.py的脚本,我们需要URL地址和HEADER请求头来抓取页面,直接从Finder中复制

  将标头转换为 Json

  # coding:utf-8

import requests

class WxCrawler(object):

# 复制出来的 Headers,注意这个 x-wechat-key,有时间限制,会过期。当返回的内容出现 验证 的情况,就需要换 x-wechat-key 了

headers = """Connection: keep-alive

x-wechat-uin: MTY4MTI3NDIxNg%3D%3D

x-wechat-key: 5ab2dd82e79bc5343ac5fb7fd20d72509db0ee1772b1043c894b24d441af288ae942feb4cfb4d234f00a4a5ab88c5b625d415b83df4b536d99befc096448d80cfd5a7fcd33380341aa592d070b1399a1

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Linux; Android 10; GM1900 Build/QKQ1.190716.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/67.0.3396.87 XWEB/992 MMWEBSDK/191102 Mobile Safari/537.36 MMWEBID/7220 MicroMessenger/7.0.9.1560(0x27000933) Process/toolsmp NetType/WIFI Language/zh_CN ABI/arm64

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/wxpic,image/apng,*/*;q=0.8

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,en-US;q=0.9

Cookie: wxuin=1681274216; devicetype=android-29; version=27000933; lang=zh_CN; pass_ticket=JvAJfzySl6uLWYdYwzyQ+4OqrqiZ2zfaI4F2OCVR7omYOmTjYNKalCFbr75X+T6K; rewardsn=; wxtokenkey=777; wap_sid2=COjq2KEGElxBTmotQWtVY2Iwb3BZRkIzd0Y0SnpaUG1HNTQ0SDA4UGJOZi1kaFdFbkl1MHUyYkRKX2xiWFU5VVhDNXBkQlY0U0pRXzlCZW9qZ29oYW9DWmZYOTdmQTBFQUFBfjD+hInvBTgNQJVO

X-Requested-With: com.tencent.mm"""

url = "https://mp.weixin.qq .com/mp/profile_ext?action=home&__biz=MjEwNDI4NTA2MQ==&scene=123&devicetype=android-29&version=27000933&lang=zh_CN&nettype=WIFI&a8scene=7&session_us=wxid_2574365742721&pass_ticket=JvAJfzySl6uLWYdYwzyQ%2B4OqrqiZ2zfaI4F2OCVR7omYOmTjYNKalCFbr75X%2BT6K&wx_header=1"

# 将 Headers 转换为 字典

def header_to_dict(self):

headers = self.headers.split("\n")

headers_dict = dict()

for h in headers:

k,v = h.split(":")

headers_dict[k.strip()] = v.strip()

return headers_dict;

def run(self):

headers = self.header_to_dict()

response = requests.get(self.url, headers=headers, verify=False)

print(response.text)

if __name__ == "__main__":

wx = WxCrawler()

wx.run()

  下图是控制台打印的内容,其中JavaScript中变量msgList的值就是需要的内容

  下一步是提取msgList的内容,使用正则表达式提取内容,返回一个文章list

  import re

import html

import json

def article_list(self, context):

rex = "msgList = '({.*?})'"

pattern = re.compile(pattern=rex, flags=re.S)

match = pattern.search(context)

if match:

data = match.group(1)

data = html.unescape(data)

data = json.loads(data)

articles = data.get("list")

return articles

  以下是解析msgList的结果

  title:文章title content_url:文章link source_url:原链接,可能为空 摘要:摘要封面:封面图片 datetime:推送时间

  其他内容存储在 multi_app_msg_item_list 中

  {'comm_msg_info':

{

'id': 1000033457,

'type': 49,

'datetime': 1575101627,

'fakeid': '2104285061',

'status': 2,

'content': ''

},

'app_msg_ext_info':

{

'title': '快查手机!5000多张人脸照正被贱卖,数据曝光令人触目惊心!',

'digest': '谁有权收集人脸信息?',

'content': '',

'fileid': 0,

'content_url': 'http:\\/\\/mp.weixin.qq.com\\/s?__biz=MjEwNDI4NTA2MQ==&mid=2651824634&idx=1&sn=3e4c8eb35abb1b09a4077064ba0c44c8&chksm=4ea8211079dfa8065435409f4d3d3538ad28ddc197063a7e1820dafb9ee23beefca59c3b32d4&scene=27#wechat_redirect',

'source_url': '',

'cover': 'http:\\/\\/mmbiz.qpic.cn\\/mmbiz_jpg\\/G8vkERUJibkstwkIvXB960sMOyQdYF2x2qibTxAIq2eUljRbB6zqBq6ziaiaVqm8GtEWticE6zAYGUYqKJ3SMuvv1EQ\\/0?wx_fmt=jpeg',

'subtype': 9,

'is_multi': 1,

'multi_app_msg_item_list':

[{

'title': '先有鸡还是先有蛋?6.1亿年前的胚胎化石揭晓了',

'digest': '解决了困扰大申君20多年的问题',

'content': '',

'fileid': 0,

'content_url': 'http:\\/\\/mp.weixin.qq.com\\/s?__biz=MjEwNDI4NTA2MQ==&mid=2651824634&idx=2&sn=07b95d31efa9f56d460a16bca817f30d&chksm=4ea8211079dfa8068f42bf0e5df076a95ee3c24cab71294632fe587bcc9238c1a7fb7cd9629b&scene=27#wechat_redirect',

'source_url': '',

'cover': 'http:\\/\\/mmbiz.qpic.cn\\/mmbiz_jpg\\/yl6JkZAE3S92BESibpZgTPE1BcBhSLiaGOgpgVicaLdkIXGExe3mYdyVkE2SDXL1x2lFxldeXu8qXQYwtnx9vibibzQ\\/0?wx_fmt=jpeg',

'author': '',

'copyright_stat': 100,

'del_flag': 1,

'item_show_type': 0,

'audio_fileid': 0,

'duration': 0,

'play_url': '',

'malicious_title_reason_id': 0,

'malicious_content_type': 0

},

{

'title': '外交部惊现“李佳琦”!网友直呼:“OMG被种草了!”',

'digest': '种草了!',

'content': '', ...}

...]

  获取单个页面

  在上一节中,我们可以得到app_msg_ext_info中的content_url地址,需要从comm_msg_info的不规则Json中获取。这是使用demjson模块完成不规则的comm_msg_info。

  安装 demjson 模块

  pip3 install demjson

  import demjson

# 获取单个文章的URL

content_url_array = []

def content_url(self, articles):

content_url = []

for a in articles:

a = str(a).replace("\/", "/")

a = demjson.decode(a)

content_url_array.append(a['app_msg_ext_info']["content_url"])

# 取更多的

for multi in a['app_msg_ext_info']["multi_app_msg_item_list"]:

self.content_url_array.append(multi['content_url'])

return content_url

  获取单个文章的地址后,使用requests.get()函数获取HTML页面并解析

  

# 解析单个文章

def parse_article(self, headers, content_url):

for i in content_url:

content_response = requests.get(i, headers=headers, verify=False)

with open("wx.html", "wb") as f:

f.write(content_response.content)

html = open("wx.html", encoding="utf-8").read()

soup_body = BeautifulSoup(html, "html.parser")

context = soup_body.find('div', id = 'js_content').text.strip()

print(context)

  所有历史文章

  当你向下滑动历史消息时,出现Loading...这是公众号正在翻页的历史消息。查Fiddler,公众号请求的地址是.com/mp/profile_ext? action=getmsg&__biz...

  翻页请求地址返回结果,一般可以分析。

  ret:是否成功,0代表成功msg_count:每页的条目数 can_msg_continue:是否继续翻页,1代表继续翻页general_msg_list:数据,包括标题、文章地址等信息

  def page(self, headers):

response = requests.get(self.page_url, headers=headers, verify=False)

result = response.json()

if result.get("ret") == 0:

msg_list = result.get("general_msg_list")

msg_list = demjson.decode(msg_list)

self.content_url(msg_list["list"])

#递归

self.page(headers)

else:

print("无法获取内容")

  总结

  这里已经爬取了公众号的内容,但尚未爬取单个文章的阅读和查看数量。想想看,如何抓取这些内容变化?

  示例代码:

  PS:公众号内回复:Python,可以进入Python新手学习交流群,一起

  -END-

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线