精华内容
下载资源
问答
  • 基于 Python 实现微信公众号爬虫 『课程目录』: 0微信公众号爬虫的基本原理 1使用 Requests 实现一个简单网页爬虫 2使用 Fiddler 抓包分析公众号请求过程 3抓取微信公众号第一篇文章 4...
  • # 项目简介 基于搜狗微信搜索的微信公众号爬虫 可以抓取指定公众号的文章信息
  • 基于搜狗微信搜索的微信公众号爬虫接口
  • 很多的微信公众号都提供了质量比较高的文章阅读,对于自己喜欢的微信公众号,所以想做个微信公众号爬虫,爬取相关公众号的所有文章。抓取公众号的所有的文章,需要获取两个比较重要的参数。一个是微信公众号的唯一ID...

    很多的微信公众号都提供了质量比较高的文章阅读,对于自己喜欢的微信公众号,所以想做个微信公众号爬虫,爬取相关公众号的所有文章。抓取公众号的所有的文章,需要获取两个比较重要的参数。一个是微信公众号的唯一ID(__biz)和获取单一公众号的文章权限值wap_sid2。接下来说一下思路。

    爬取思路:

    要想获取微信公众号的爬虫,首先要唯一标识这个微信公众号,所以要获取这个微信公众号的id值(即__biz)。看了比较多的相关文章,很多获取__biz的值比较机械,单纯手动复制取__biz;现在搜狗引擎与微信公众号对接,为我们提供了一个很好的获取途径,微信公众号源码里面有该号的__biz值(可以从这个途径获取);但是搜狗引擎对微信公众号有限制,只显示最近10条文章,所以我们单纯只从搜狗引擎获取__biz值和通过搜狗搜索任意关键词公众号列表。

    下面是搜狗搜索微信公众号的URL地址,其中query的python是搜索的关键词,其他可以不变。

    http://weixin.sogou.com/weixin?type=1&s_from=input&query=python&ie=utf8&_sug_=n&_sug_type_=

    复制代码

    搜索的结果页面:

    1

    查看源代码

    在源代码中可以发现每一个公众号的链接,都是位于id为sougou_vr_11002301_box_n(n为整数如1,2,3等)下面的a标签href属性值。通过xpath语法可以获取,其中n的位置可以按规律顺序获取:

    //*[@id="sogou_vr_11002301_box_n"]/div/div[2]/p[1]/a

    复制代码

    获取到单个公众号的地址如下所示:

    http://mp.weixin.qq.com/profile?src=3&timestamp=1508003829&ver=1&signature=Eu9LOYSA47p6WE0mojhMtFR-gSr7zsQOYo6*w5VxrUgy7RbCsdkuzfFQ1RiSgM3i9buMZPrYzmOne6mJxCtW*g==

    复制代码

    打开单个公众号链接,获取公众号源码,取其中微信公众号的id值:

    1

    //其中biz值就是微信公众号的唯一id值。前面和后面省略了大部分代码;该段代码位于script标签里面;该代码还有最近10条文章的数据,如果单纯想获取最近10条,可以通过正则表达式来直接获取

    var biz = "MzIwNDA1OTM4NQ==" || "";

    var src = "3" ;

    var ver = "1" ;

    var timestamp = "1508003829" ;

    var signature = "Eu9LOYSA47p6WE0mojhMtFR-gSr7zsQOYo6*w5VxrUgy7RbCsdkuzfFQ1RiSgM3i9buMZPrYzmOne6mJxCtW*g==" ;

    var name="python6359"||"python";

    复制代码

    获取到微信公众号的id值之后,就是要获取wap_sid值(即单个微信公众号的文章权限值。)这个部分从微信客户端获取,接下来通过Fiddler抓包工具获取,如果不知道抓包工具的环境搭建,可以参考 fiddler抓取摩拜单车数据包

    获取微信公众号文章的权限值的url:

    GET /mp/profile_ext?action=home&__biz=MjM5MDI1ODUyMA==&scene=124&devicetype=iOS10.0.1&version=16051220&lang=zh_CN&nettype=WIFI&a8scene=3&fontScale=100&pass_ticket=ji%2B3JbA2NNExGwdNCoIa91sbgwDmSmHsdZhHP5eo%2Bgun%2By2V3lxc34GQy3W5u8mE&wx_header=1 HTTP/1.1

    复制代码

    相应的请求头,其中x-wechat-key是隔段时间更换一次,所以需要定时更换一次;X-WECHAT-UIN可以不变。pass_ticket也可以一段时间内不做改变:

    'Host':'mp.weixin.qq.com',

    # 'X-WECHAT-KEY': 'a83687cde3ca46be517cdbcba60732159f229a03507e9afa1e0dfee00e3cf00562aee022e84b9011924fdbb0c7af8c647c33b1338b11ebdc8893d5df41dd34a536e1af5b48d15c87b4aef629ad8685f3',

    'X-WECHAT-KEY': '33c1fdebcfc1d1ecd9df5003dc9d9ccb6a1f5458eb704e58a05e80c73e8793dede6b52115a74a515d4d12c9a6f2d8f00238afe17cca3635d80d661a612a4a0bf48a2547516b12030efd8a224548636d2',

    'X-WECHAT-UIN':'MTU2MzIxNjQwMQ%3D%3D',

    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',

    'User-Agent':'Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Mobile/14A403 MicroMessenger/6.5.18 NetType/WIFI Language/zh_CN',

    'Accept-Language':'zh-cn',

    'Accept-Encoding':'gzip, deflate',

    'Connection':'keep-alive',

    'Cookie':'wxuin=1563216401;pass_ticket=oQDl45NRtfvQIxv2j2pYDSOOeflIXU7V3x1TUaOTpi6SkMp2B3fJwF6TE40ATCpU;ua_id=Wz1u21T8nrdNEyNaAAAAAOcFaBcyz4SH5DoQIVDcnao=;pgv_pvid=7103943278;sd_cookie_crttime=1501115135519;sd_userid=8661501115135519;3g_guest_id=-8872936809911279616;tvfe_boss_uuid=8ed9ed1b3a838836;mobileUV=1_15c8d374ca8_da9c8;pgv_pvi=8005854208',

    'Referer':"https://mp.weixin.qq.com/mp/getmasssendmsg?__biz=MjM5MzI5MTQ1Mg==&devicetype=iOS10.0.1&version=16051220&lang=zh_CN&nettype=WIFI&ascene=3&fontScale=100&pass_ticket=oQDl45NRtfvQIxv2j2pYDSOOeflIXU7V3x1TUaOTpi6SkMp2B3fJwF6TE40ATCpU&wx_header=1"

    复制代码

    上面的请求url获取的返回响应头,是设置wap_sid2获取单一公众号文章的权限值,我们就是要获取set-cookies中的wap-sid2值:

    HTTP/1.1 200 OK

    Content-Type: text/html; charset=UTF-8

    Cache-Control: no-cache, must-revalidate

    Strict-Transport-Security: max-age=15552000

    Set-Cookie: wxuin=1563216401; Path=/; HttpOnly

    Set-Cookie: pass_ticket=ji+3JbA2NNExGwdNCoIa91sbgwDmSmHsdZhHP5eo+gun+y2V3lxc34GQy3W5u8mE; Path=/; HttpOnly

    Set-Cookie: wap_sid2=CJGUs+kFElxER01KN1ZkVElJMUdhTktDUUk2LUZHNkFwT1Rzc1EwUWpWaW5ZMHlFQi15cUo1VWFjamNLM3pjdzNCbDc2ZFZpOW0xeDdPb0czWXNuQUdmbVdyOFZiNTREQUFBfjC+7YvPBTgMQJRO; Path=/; HttpOnly

    Connection: keep-alive

    Content-Length: 37211

    复制代码

    获取公众号列表数据

    获取wap_sid2权限值

    获取到公众号id值__biz和权限值wap_sid2;我们就可以构造请求获取文章列表了。其中mongodb操作是为了获取公众号id值,然后根据id值,获取wap_sid2值,然后把id值和wap_sid2对应入库。

    # -*- coding: utf-8 -*-

    from scrapy import Spider,Request

    from .mongo import MongoOperate

    import re

    from wechatSpider.items import GetsessionspiderItem

    from .settings import *

    class GetsessionSpider(Spider):

    name = "getSession"

    allowed_domains = ["mp.weixin.qq.com"]

    start_urls = ['https://mp.weixin.qq.com/']

    headers={

    'Host':'mp.weixin.qq.com',

    # 'X-WECHAT-KEY': 'a83687cde3ca46be517cdbcba60732159f229a03507e9afa1e0dfee00e3cf00562aee022e84b9011924fdbb0c7af8c647c33b1338b11ebdc8893d5df41dd34a536e1af5b48d15c87b4aef629ad8685f3',

    'X-WECHAT-KEY': '33c1fdebcfc1d1ecd9df5003dc9d9ccb6a1f5458eb704e58a05e80c73e8793dede6b52115a74a515d4d12c9a6f2d8f00238afe17cca3635d80d661a612a4a0bf48a2547516b12030efd8a224548636d2',

    'X-WECHAT-UIN':'MTU2MzIxNjQwMQ%3D%3D',

    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',

    'User-Agent':'Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Mobile/14A403 MicroMessenger/6.5.18 NetType/WIFI Language/zh_CN',

    'Accept-Language':'zh-cn',

    'Accept-Encoding':'gzip, deflate',

    'Connection':'keep-alive',

    'Cookie':'wxuin=1563216401;pass_ticket=oQDl45NRtfvQIxv2j2pYDSOOeflIXU7V3x1TUaOTpi6SkMp2B3fJwF6TE40ATCpU;ua_id=Wz1u21T8nrdNEyNaAAAAAOcFaBcyz4SH5DoQIVDcnao=;pgv_pvid=7103943278;sd_cookie_crttime=1501115135519;sd_userid=8661501115135519;3g_guest_id=-8872936809911279616;tvfe_boss_uuid=8ed9ed1b3a838836;mobileUV=1_15c8d374ca8_da9c8;pgv_pvi=8005854208',

    'Referer':"https://mp.weixin.qq.com/mp/getmasssendmsg?__biz=MjM5MzI5MTQ1Mg==&devicetype=iOS10.0.1&version=16051220&lang=zh_CN&nettype=WIFI&ascene=3&fontScale=100&pass_ticket=oQDl45NRtfvQIxv2j2pYDSOOeflIXU7V3x1TUaOTpi6SkMp2B3fJwF6TE40ATCpU&wx_header=1"

    }

    # 查看历史消息列表,现在需要捕获`wap_sid2`这个值,来获取访问权限

    url="https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz={biz}&scene=124&devicetype=iOS10.0.1&version=16051220&lang=zh_CN&nettype=WIFI&a8scene=3&fontScale=100&pass_ticket=oQDl45NRtfvQIxv2j2pYDSOOeflIXU7V3x1TUaOTpi6SkMp2B3fJwF6TE40ATCpU&wx_header=1"

    def start_requests(self):

    MongoObj=MongoOperate(MONGO_URI,MONGO_DATABASE,MONGO_USER,MONGO_PASS,WECHATID)

    MongoObj.connect()

    items=MongoObj.finddata()

    for item in items:

    biz=item["wechatID"]

    yield Request(url=self.url.format(biz=biz),dont_filter=True,headers=self.headers,callback=self.parse,meta={"proxy":"http://127.0.0.1:8888","biz":biz})

    def parse(self, response):

    item=GetsessionspiderItem()

    data=response.headers

    needCon=data["Set-Cookie"]

    wap=needCon.decode("utf-8")

    wap=wap.split(';')

    wap=wap[0].split('=')

    wap_sid2=wap[1]

    print(wap_sid2)

    item["biz"]=response.request.meta["biz"]

    item["wap_sid2"]=str(wap_sid2)

    yield item

    # print(item)

    复制代码

    1

    获取文章数据列表

    在mongoDB中保存着一个公众号的id值及对应的wap_sid2值,接下来构造请求文章的值,也是获取公众号文章列表url。

    # -*- coding: utf-8 -*-

    import scrapy

    from scrapy import Request

    from .mongo import MongoOperate

    import json

    from .settings import *

    class DataSpider(scrapy.Spider):

    name = "data"

    allowed_domains = ["mp.weixin.qq.com"]

    start_urls = ['https://mp.weixin.qq.com/']

    count=10

    url="https://mp.weixin.qq.com/mp/profile_ext?action=getmsg&__biz={biz}&f=json&offset={index}&count=10&is_ok=1&scene=124&uin=777&key=777&pass_ticket=ULeI%2BILkTLA2IpuIDqbIla4jG6zBTm1jj75UIZCgIUAFzOX29YQeTm5UKYuXU6JY&wxtoken=&appmsg_token=925_%252B4oEmoVo6AFzfOotcwPrPnBvKbEdnLNzg5mK8Q~~&x5=0&f=json"

    def start_requests(self):

    MongoObj=MongoOperate(MONGO_URI,MONGO_DATABASE,MONGO_USER,MONGO_PASS,RESPONSE)

    MongoObj.connect()

    items=MongoObj.finddata()

    for item in items:

    headers={

    'Accept-Encoding':'gzip, deflate',

    'Connection':'keep-alive',

    'Accept':'*/*',

    'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Mobile/14A403 MicroMessenger/6.5.18 NetType/WIFI Language/zh_CN',

    'Accept-Language': 'zh-cn',

    'X-Requested-With': 'XMLHttpRequest',

    'X-WECHAT-KEY': '62526065241838a5d44f7e7e14d5ffa3e87f079dc50a66e615fe9b6169c8fdde0f7b9f36f3897212092d73a3a223ffd21514b690dd8503b774918d8e86dfabbf46d1aedb66a2c7d29b8cc4f017eadee6',

    'X-WECHAT-UIN': 'MTU2MzIxNjQwMQ%3D%3D',

    'Cookie':';wxuin=1563216401;pass_ticket=oQDl45NRtfvQIxv2j2pYDSOOeflIXU7V3x1TUaOTpi6SkMp2B3fJwF6TE40ATCpU;ua_id=Wz1u21T8nrdNEyNaAAAAAOcFaBcyz4SH5DoQIVDcnao=;pgv_pvid=7103943278;sd_cookie_crttime=1501115135519;sd_userid=8661501115135519;3g_guest_id=-8872936809911279616;tvfe_boss_uuid=8ed9ed1b3a838836;mobileUV=1_15c8d374ca8_da9c8;pgv_pvi=8005854208'

    }

    biz=item["biz"]

    #主要验证是wap_sid2;pass_ticket不一样无所谓

    headers["Cookie"]="wap_sid2="+item["wap_sid2"]+headers["Cookie"]

    yield Request(url=self.url.format(biz=biz,index="10"),headers=headers,callback=self.parse,dont_filter=True,meta={"biz":biz,"headers":headers},)

    def parse(self, response):

    biz=response.request.meta["biz"]

    headers=response.request.meta["headers"]

    resText=json.loads(response.text)

    print(resText)

    list=json.loads(resText["general_msg_list"])

    print(list)

    yield list

    if resText["can_msg_continue"]==1:

    self.count=self.count+10

    yield Request(url=self.url.format(biz=biz,index=str(self.count)),headers=headers,callback=self.parse,dont_filter=True,meta={"biz":biz,"headers":headers})

    else:

    print("end")

    复制代码

    获取到的数据如下图所示:

    1

    获取wap_sid另外一种思路

    在爬取的过程中,有时候经过抓包,想获取一个重定向的网页的响应头;但是响应头cookies已经设置read only,我们想通过这里获取权限值,可以通过设置Fiddler的rules来生成保存响应文件。在微信文章爬取过程中,虽然也是想通过这种方式获取权限值。但是发觉自己是忽略了请求头x-wechat-key和x-wechat-uin所以获取不到。所以这种方式在该项目并不需要。但是提供一种获取动态设置cookies值,然后重定向到新页面的响应头方法,比如获取 mp.weixin.qq.com/mp/profile_…

    1

    在Fiddler添加以下代码,然后在桌面生成一个2.txt文件,上面保存返回的响应头:

    static function OnBeforeResponse(oSession: Session) {

    if (oSession.HostnameIs("mp.weixin.qq.com") && oSession.uriContains("/mp/profile_ext?action=home")) {

    oSession["ui-color"] = "orange";

    oSession.SaveResponse("C:\\Users\\Administrator\\Desktop\\2.txt",false);

    //oSession.SaveResponseBody("C:\\Users\\Administrator\\Desktop\\1.txt")

    }

    if (m_Hide304s && oSession.responseCode == 304) {

    oSession["ui-hide"] = "true";

    }

    }

    复制代码

    1

    展开全文
  • Python爬虫五:微信公众号爬虫-2018.9

    万次阅读 多人点赞 2018-09-08 23:26:19
    ---全部文章: 京东爬虫 、链家爬虫、美团爬虫、微信公众号爬虫、字体反爬、Django笔记、阿里云部署、vi\vim入门---- 分析:关于微信公众号的爬取,网上搜索了一下,主要有几种方法: 一、搜狗微信公众平台 ...

    环境:Windows7 +Python3.6+Pycharm2017

    目标:抓取微信公众号全部历史文章(文章名+url)保存到本地csv。

    ---全部文章: 京东爬虫 、链家爬虫美团爬虫微信公众号爬虫字体反爬Django笔记阿里云部署vi\vim入门----

    分析:关于微信公众号的爬取,网上搜索了一下,主要有几种方法:

    一、搜狗微信公众平台 http://weixin.sogou.com/ ,有个问题就是这里抓的文章一个不能把公众号文章全部抓全,还有就是文章的地址好像不是永久地址。

    二、公众号平台文章调用接口 https://mp.weixin.qq.com/ ,就是你自己要先申请一个公众号,编辑文章的时候有个引用文章,但是这种方法好像有次数限制。具体可以参考以下文章 链接。 一二两种我自己都没试过。

    三、APP抓包,通过抓包分析请求参数,然后构造请求。

    基本思路:

        抓包工具这里用的是Anyproxy,打开手机微信,进入公众号的历史文章页面,下拉会不断加载历史文章,每次10条。抓包发现这是一个get请求,url如下:

    https://mp.weixin.qq.com/mp/profile_ext?action=getmsg&__biz=MzU2MzA2ODk3Nw==&f=json&offset=10&count=10&is_ok=1&scene=124&uin=777&key=777&pass_ticket=%2F%2FMLfYzV4VmptckJ%2BGC%2FEMbuBaYdCzplfP7pig2nHKORwHh%2FKcSp5ufJNIY4R6Y6&wxtoken=&appmsg_token=973_9bX%252FVHxGVbz3AvGoFZHVNBOf1ygPLteCjhz8aA~~&x5=1&f=json

    url中主要有三个参数:_biz   公众号的id;offset  翻页参数,每次增加10;appmsg_token 这是一个加密参数,有一段有效期。我们如果要构造请求的话,主要的问题就是这个appmsg_token参数,显然去破解这个参数是怎么生成的难度比较大。本文采用的办法是利用手机微信app发送请求,然后用代理软件Anyproxy截获这个请求的appmsg_token,还有cookie,返回给我们的爬虫程序。

    原理就是这么简单,你可以用一个抓包软件抓包,然后手动的将appmsg_token、cookie、headers信息加到你的爬虫代码中,就可以抓取了。爬太快的话会封ip,实际测试每次请求sleep1秒,一个appmsg_token可以把人民日报历史文章全部抓完。本文内容比较多,但是基本上都是为了实现上面步骤的自动化。

    本文用到的工具有:Anyproxy抓包工具,adb(一个安卓调试工具,借此可用实现电脑控制手机操作,如点击,滑动等),aiohttp(其他web框架也可以)搭建一个简单的web服务,用以将抓包获取的参数传递给爬虫代码。

    实现逻辑如下:手机连接Anyproxy代理,再通过数据线连接电脑(连接adb),打开微信公众号历史文章页面。开启aiohttp的web服务,启动爬虫代码。首先会去获取token和cookie,方法是用adb控制手机下拉加载更多的历史文章触发请求。然后Anyproxy捕获到该请求,将请求的appmsg_token、cookie参数通过post请求发送到aiohttp的web服务器上,然后爬虫代码通过get请求访问aiohttp的web服务器获取appmsg_token、cookie参数,然后开始爬取。

    具体实现:

    一、Anyproxy安装使用

    Anyproxy是阿里开发的一款代理服务器,支持基于nodejs的二次开发。我们可以在中间对请求或者响应做一些修改,如中间人攻击。

    安装:1、首先需要安装nodejs,去官网下载,点击安装就行。2、装好nodejs后在cmd窗口输入 npm install -g anyproxy 进行安装。我自己安装过程中遇到个错误,提示是缺少一个react库,我自己去网上下了一个,文件夹名称改为react,然后放到nodejs下面的lib文件夹中。我看网上也没提到这个问题,写下。安装如果遇到其他问题自行百度下应该都能解决。

     3、装好anyproxy后,如果我们要监听https请求,还需要安装证书。电脑端、手机端都需要安装。电脑端整数安装方式:在cmd窗口输入 anyproxy-ca  (中间没有空格),会生成一个证书,找到这个证书点击设置为受信任的证书。手机端证书下载,我用的是安卓机,苹果好像稍微有点不一样。先在cmd中输入命令 anyproxy 运行代理,然后再用浏览器打开 http://127.0.0.1:8002/ ,可以在web界面上能看到所有的请求信息。

     http://127.0.0.1:8002/ web监控界面如上图所示,点击左边的RootCA会弹出二维码,用手机扫描二维码即可下载证书并安装。我自己在安装的时候还要求输入手机密码,就是设置指纹时设置的密码。上图右上角的圆球点击后会出现一串地址,第一个就是后面手机设置代理时的地址。

    安装好证书后,在cmd窗口输入命令运行anyproxy,几条常用命令如下:

    anyproxy     #运行anyproxy,不监听https请求
    
    anyproxy -i  #运行anyproxy,监听https请求
    
    anyproxy -i --rule F:\XX\X\sample.js  
                 #运行anyproxy,监听https请求,并执行sample.js中的代码(二次开发)

    手机设置代理,手机和电脑连接一个wifi,不同手机设置可能不一样。我的是点进当前连接的wifi,代理设置--手动--然后输入主机名和端口,端口默认8001,主机名就是上面提到的那个地址。

     手机设置好代理后,点开微信公众号文章,就能在web页面观察到请求,点击请求可以查看详细信息,左边的Fliter可以做筛选。

    以新京报为例,点击进入公众号历史消息,首页的10条消息是一个get请求,返回是一段html代码,如下图一。继续往下拉,加载更多后,我们发现加载更多的也是一个get请求,返回的是json数据。这两个get请求不一样,但是发现首页的10条消息也可以用加载更多的get请求获得,offset设置为0。

     

     

     正如上文所述,构造加载更多的get请求需要三个参数,_biz  公众号的id;offset  翻页参数;appmsg_token 这是一个加密参数,一段时间内有效。主要的我们就是需要appmsg_token参数和请求的cookie,这里就需要使用anyproxy的二次开发功能,当代理检测到app发送了加载更多的请求,获取这个请求的url,cookie,通过post请求发送到aiohttp搭建的web服务器上,然后爬虫代码再从服务器上获取这些参数。anyproxy监听和发post请求的代码如下,是基于nodejs,本人也不会js,都是百度依样画葫芦。

    sample.js文件:

    
    var http = require('http'); //引用http模块
    var querystring = require('querystring');//引用querystring模块
    //构造一个函数,用于发送post请求,发送的内容为contents
    function post_data(contents) {
        var options = {
            host: '127.0.0.1',   //本地web服务器的地址端口
            port: '8080',
            path: '/',
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Content-Length': contents.length }
        }
    
        var req = http.request(options, function (res) {
            res.setEncoding('utf8');
            res.on('data', function (data) {
                console.log("data:", data);
            });
        });
        req.write(contents);
        req.end;
    }
    
    
    //anyproxy固定格式
    module.exports = {
      summary: 'a rule to get url and cookie', //一段代码功能介绍
        //在request发送前执行,下面的if通过正则匹配请求的url来找到加载更多的请求,然后获取url、cookie
      *beforeSendRequest(requestDetail) {
        if (/mp.weixin.qq.com\/mp\/profile_ext\?action=getmsg&__biz/i.test(requestDetail.url)) {
            console.log('***********抓取到目标**********')
            console.log(requestDetail.requestOptions['headers'])
            var contents=querystring.stringify({
                 'url':requestDetail.url,
                 'cookie':requestDetail.requestOptions['headers']['Cookie']});
            post_data(contents) //发送post请求
    
            return null
        }
    
      },
    };

    二、aiohttp搭建本地web服务

    aiohttp是一个异步的框架,可以建web服务,也可以用来发请求。当然也可以用其他的web框架。

    首先安装 : pip install aiohttp

    路由系统定义两个函数,get和give,当有post请求过来时执行函数get,当有get请求过来时执行give函数。代码如下:

    from aiohttp import web
    import re
    #接收anyproxy的post请求并处理
    async def get(request):
        n=await request.post()
        url=n['url']
        cookie=n['cookie']
        # biz=re.search('biz=.{14}==',url).group()   #从url中提取出_biz
        token = re.search('appmsg_token.+json', url).group() #从url中提取出appmsg_token
        print('获取token:  ',token)
        print('获取cookie:  ',cookie)
        data={'token':token,'cookie':cookie}
        p_list.append(data)
        print('当前列表长度:',len(p_list))
        return web.Response(text='你好,收到信息')
    #接收爬虫代码的get请求并返回appmsg_token和cookie
    async def give(request):
        print('开始发送appmsg_token和cookie')
        d=p_list.pop()
        return web.Response(text=str(d))
    
    p_list=[]  #用于存储appmsg_token和cookie
    app=web.Application()
    app.add_routes([web.post('/',get),web.get('/',give)])  #路由定义,有post请求访问127.0.0.1:8080,执行get函数,有get请求访问127.0.0.1:8080,执行give函数
    web.run_app(app,host='127.0.0.1',port=8080) #定义web服务器运行的位置 端口

     

    三、adb的安装使用

    adb主要用来实现电脑对手机的控制,用代码自动完成手机微信公众号的操作。

    adb安装可以参考 文章 ,直接下载 下面的文件,解压后有四个文件,添加到系统环境变量。cmd输入adb,出现一长串信息就安装ok了。

    百度网盘链接: https://pan.baidu.com/s/1pMxVo0lLnSoAmUp9Xpgzng   密码: yh8q  

    手机用数据线连接电脑,打开usb调试,可以在cmd中输入命令控制,常见命令如下

    adb shell input swipe 100 200  800 200 100 
        #从点(100,200)滑动到(800,200)用时100ms(时间可以不加),前面是x坐标,后面是y,坐标圆点是屏幕左上角
    
    adb shell input tap 557 1578  #点击屏幕上的点(557,1578)
    
    
    用python实现:直接调用os库
    
    import os
    
    os.system('adb shell input swipe 100 200  800 200 100')
        
    os.system('adb shell input tap 557 1578')

    四、爬虫主程序

    首先手机usb连好电脑,开启usb调试,开启anyproxy代理,手机设置好代理,开启web服务。手机点开人民日报历史消息页面,如下图一,运行爬虫主程序,利用adb命令 屏幕左边缘向右滑动返回公众号的基本信息页面,如下图二,然后再点击【查看历史消息】再次进入到图一历史消息页面,然后利用滑动操作触发加载更多。每次重新进入历史消息页面生成新的appmsg_token参数。程序运行过程手机需要保持亮屏。这里还利用一点就是一个公众号的appmsg_token也可以用以请求其他公众号,但是也不是全部都适用,有的也不行。

     爬虫程序代码如下,输入为公众号biz号,输出为公众号历史文章的名称和url。

    import requests
    import json
    import csv
    import time
    import os
    
    def get_token():
        os.system('adb shell input swipe 0 200  800 200')  #从屏幕左边缘右滑返回上一级
        time.sleep(0.5)
        os.system('adb shell input tap 557 1578')          #点击 【查看历史消息】 进入历史消息页面,坐标每个手机不一样
        time.sleep(2)
        os.system('adb shell input swipe 500 1800  500 300 100') #两次向上滑动触发加载更多
        os.system('adb shell input swipe 500 1800  500 300 100')
        time.sleep(0.1)
        url='http://127.0.0.1:8080'
        r=requests.get(url)   #向本地web服务器发送get请求获取appmsg_token和cookie
        d=eval(r.text)
        print('获取token:',d)
        # token = d['token']
        # cookie = d['cookie']
        return(d)
    
    def crow(biz):
        MARK=0 #一个公众号文章是否抓完的标志位,1表示抓完
        data=get_token()
        token=data['token']
        cookie=data['cookie']
        n=0
        while MARK==0:
            time.sleep(0.5)
            pages = str(10 * n)
            url = 'https://mp.weixin.qq.com/mp/profile_ext?action=getmsg&__biz='+biz+'&f=json&offset=' +pages+ '&count=10&is_ok=1&scene=124&uin=777&key=777&pass_ticket=%2F%2FMLfYzV4VmptckJ%2BGC%2FEMbuBaYdCzplfP7pig2nHKORwHh%2FKcSp5ufJNIY4R6Y6&wxtoken=&'+token
            head = {'Host': 'mp.weixin.qq.com',
                    'Connection': 'keep-alive',
                    'X-Requested-With': 'XMLHttpRequest',
                    'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; GN8002 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044205 Mobile Safari/537.36 MicroMessenger/6.6.3.1260(0x26060339) NetType/WIFI Language/zh_CN',
                    'Accept': '*/*',
                    'Referer': 'https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MjM5NzAwMzU0MA==&scene=124&devicetype=android-23&version=26060339&lang=zh_CN&nettype=WIFI&a8scene=3&pass_ticket=5IruuVAhjeQ22KmpbBJX10LUhvreqP%2F4zCi0%2FlKRAYVSGufFu4EDGCytd7oIWNkV&wx_header=1',
                    'Accept-Encoding': 'gzip, deflate',
                    'Accept-Language': 'zh-CN,en-US;q=0.8',
                    'Q-UA2': 'QV=3&PL=ADR&PR=WX&PP=com.tencent.mm&PPVN=6.6.3&TBSVC=43603&CO=BK&COVC=044205&PB=GE&VE=GA&DE=PHONE&CHID=0&LCID=9422&MO= GN8002 &RL=1080*1920&OS=6.0&API=23',
                    'Q-GUID': '37319016da4caf7783df5bf913b788cb',
                    'Q-Auth': '31045b957cf33acf31e40be2f3e71c5217597676a9729f1b',
                    'cookie': cookie
                    }
            try:
                r = requests.get(url, headers=head,timeout=5)
                html = json.loads(r.text)
                if len(html)==9:  #判断下返回的json消息体是否是正常的消息体
                    datas0 = html['general_msg_list']
                    datas0 = json.loads(datas0)
                    datas = datas0['list']
                    l = len(datas)
                    if l<10:
                        MARK=1
                    end=time.time()-start
                    print('*********************')
                    print('Page:%d' % n, 'Num:%d' % l,'Time:%d'%end)
                    n += 1
                    for data in datas:
                        try:
                            url_1 = data['app_msg_ext_info']['content_url']
                            title_1 = data['app_msg_ext_info']['title']
                            print(title_1)
                            print(url_1)
                            dd = data['app_msg_ext_info']['multi_app_msg_item_list']
                            #保存到本地
                            with open('weixin.csv','a',newline='',encoding='gb18030')as f:
                                write=csv.writer(f)
                                if len(dd) > 0:
                                    for d in dd:
                                        url_d = d['content_url']
                                        title_d = d['title']
                                        print(title_d)
                                        print(url_d)
                                        write.writerow([title_d,url_d])
                        except Exception as e:
                            print(e)
                            print(r.text)
                else:
                    #如果访问失效重新获得token、cookie
                    print('error')
                    print(r.text)
                    data = get_token()
                    token = data['token']
                    cookie = data['cookie']
    
            except:
                pass
        print('*******************',biz,'抓取完成***************')
    
    
    if __name__=='__main__':
        start=time.time()
        biz_list=['MzIxNDEzNzI4Mg==','MzA5OTA0NDIyMQ==','MTgwNTE3Mjg2MA==','MzA3MDM5ODY4Ng==','MjM5MDMyMzg2MA==','MzA4MjQxNjQzMA==','MzU2MzA2ODk3Nw==','MTI0MDU3NDYwMQ=='] #局座召忠、占豪、冷兔、美闻参阅、十点读书、新华网、新京报、央视新闻
        for biz in biz_list:
            crow(biz)
    

    五、结果与总结

    总结一下,微信对访问次数是有限制的,首先是封ip,访问越快封的越快。其次对每个微信号每天的请求次数也是有限制的,每秒发一次请求,大概测试下来是1500次请求左右。达到后就进不了公众号历史页面(禁24h),微信其他功能不影响。不清楚请求速度如果降下来次数是不是能增加。1500次请求,每次10条消息,一个公众号一天一条消息,按五年算就是1800条消息,可以爬完8个这样的公众号。但是有些公众号比如人民日报【官媒】这种是可以一天发多条消息的,所以这种账号数据量会比较大一些。还有就是需要关注你爬取的公众号,不关注好像也有影响。比较尴尬的一点是本来利用anyproxy、adb是为了自动化抓取,持续的抓取。结果发现瓶颈其实在微信号每天的访问次数,好像一个appmsg_token+cookie就可以差不多抓完1000多次,还不如手动复制下参数好!!!

    下图是抓取的一些数据,以及应该是人民日报 第一篇文章

    水平有限,如有错误请指正。

    ---全部文章: 京东爬虫 、链家爬虫美团爬虫微信公众号爬虫字体反爬Django笔记阿里云部署vi\vim入门----

                                                             

    欢迎关注个人微信公众号,更多案例持续更新!

                        打赏博主 

     

    展开全文
  • 微信公众号爬虫

    2019-01-30 18:14:32
    python爬取微信公众号内容 主要内容: 爬虫基本原理 爬虫工具 Requests 的基本使用 数据抓包分析工具 Fiddler 的基本使用 MongoDB 数据库的基本使用 使用 Pandas 进行数据分析 使用 Matplotlib 进行数据可视化展示
  • 基于Python微信公众号爬虫 Python是一种解释性的,高级的通用编程语言。 由Guido van Rossum创建并于1991年首次发布,Python的设计理念强调代码可读性,其显着使用了重要的空白。 它的语言结构和面向对象的方法...

    基于Python的微信公众号爬虫

    Python是一种解释性的,高级的通用编程语言。 由Guido van Rossum创建并于1991年首次发布,Python的设计理念强调代码可读性,其显着使用了重要的空白。 它的语言结构和面向对象的方法旨在帮助程序员为小型和大型项目编写清晰的逻辑代码。
    网络上关于爬虫的教程多如牛毛,但很少有看到微信公众号爬虫教程,要有也是基于搜狗微信的,不过搜狗提供的数据有诸多弊端,比如文章链接是临时的,文章没有阅读量等指标,所以我想写一个比较系统的关于如何通过手机客户端利用 Python 爬微信公众号文章的教程,并对公众号文章做数据分析,为更好地运营公众号提供决策。

    爬虫的基本原理

    爬虫就是一个自动化数据采集工具,你只要告诉它要采集哪些数据,丢给它一个 URL,就能自动地抓取数据了。其背后的基本原理就是爬虫程序向目标服务器发起 HTTP 请求,然后目标服务器返回响应结果,爬虫客户端收到响应并从中提取数据,再进行数据清洗、数据存储工作。

    爬虫的基本流程

    爬虫流程也是一个 HTTP 请求的过程,以浏览器访问一个网址为例,从用户输入 URL 开始,客户端通过 DNS 解析查询到目标服务器的 IP 地址,然后与之建立 TCP 连接,连接成功后,浏览器构造一个 HTTP 请求发送给服务器,服务器收到请求之后,从数据库查到相应的数据并封装成一个 HTTP 响应,然后将响应结果返回给浏览器,浏览器对响应内容进行数据解析、提取、渲染并最终展示在你面前。
    HTTP 协议的请求和响应都必须遵循固定的格式,只有遵循统一的 HTTP 请求格式,服务器才能正确解析不同客户端发的请求,同样地,服务器遵循统一的响应格式,客户端才得以正确解析不同网站发过来的响应。
    在这里插入图片描述

    HTTP 请求格式

    HTTP 请求由请求行、请求头、空行、请求体组成。
    请求行由三部分组成:

    1. 第一部分是请求方法,常见的请求方法有 GET、POST、PUT、DELETE、HEAD
    2. 第二部分是客户端要获取的资源路径
    3. 第三部分是客户端使用的 HTTP 协议版本号
      请求头是客户端向服务器发送请求的补充说明,比如 User-Agent 向服务器说明客户端的身份。
      请求体是客户端向服务器提交的数据,比如用户登录时需要提高的账号密码信息。请求头与请求体之间用空行隔开。请求体并不是所有的请求都有的,比如一般的GET都不会带有请求体。
      下图就是浏览器登录豆瓣时向服务器发送的HTTP POST 请求,请求体中指定了用户名和密码。
      在这里插入图片描述

    HTTP 响应格式

    HTTP 响应格式与请求的格式很相似,也是由响应行、响应头、空行、响应体组成。
    响应行也包含三部分,分别是服务端的 HTTP 版本号、响应状态码、状态说明,响应状态码常见有 200、400、404、500、502、304 等等,一般以 2 开头的表示服务器正常响应了客户端请求,4 开头表示客户端的请求有问题,5 开头表示服务器出错了,没法正确处理客户端请求。状态码说明就是对该状态码的一个简短描述。
    第二部分就是响应头,响应头与请求头对应,是服务器对该响应的一些附加说明,比如响应内容的格式是什么,响应内容的长度有多少、什么时间返回给客户端的、甚至还有一些 Cookie 信息也会放在响应头里面。
    第三部分是响应体,它才是真正的响应数据,这些数据其实就是网页的 HTML 源代码。

    展开全文
  • 微信公众号平台获取微信公众所有文章的url
  • 基于搜狗微信搜索的微信公众号爬虫接口demo
  • 基于搜狗搜索的微信公众号爬虫,使用requests模块访问公众号url链接,爬取相关文章(不能商用,要申请公众号主体同意方可进行相关操作),并用bs4模块解析获取的文章,并取得其中的合法内容
  • 基于搜狗微信搜索的微信公众号爬虫接口 我的另外一个作品: ,基于代码生成的 Lark/飞书 Go SDK,欢迎 star 。
  • 基于搜狗微信搜索的微信公众号爬虫接口
  • Python 微信公众号文章爬取

    千次阅读 多人点赞 2020-11-27 11:37:55
    Python 微信公众号文章爬取一.思路二.接口分析三.实现第一步:第二步:1.请求获取对应公众号接口,取到我们需要的fakeid2.请求获取微信公众号文章接口,取到我们需要的文章数据四.总结 一.思路 我们通过网页版的微信...

    一.思路

    我们通过网页版的微信公众平台的图文消息中的超链接获取到我们需要的接口图文消息
    超链接
    从接口中我们可以得到对应的微信公众号和对应的所有微信公众号文章。

    二.接口分析

    获取微信公众号的接口:
    https://mp.weixin.qq.com/cgi-bin/searchbiz?
    参数:
    action=search_biz
    begin=0
    count=5
    query=公众号名称
    token=每个账号对应的token值
    lang=zh_CN
    f=json
    ajax=1
    请求方式:
    GET
    所以这个接口中我们只需要得到token即可,而query则是你需要搜索的公众号,token则可以通过登录后的网页链接获取得到。
    微信公众号

    获取对应公众号的文章的接口:
    https://mp.weixin.qq.com/cgi-bin/appmsg?
    参数:
    action=list_ex
    begin=0
    count=5
    fakeid=MjM5NDAwMTA2MA==
    type=9
    query=
    token=557131216
    lang=zh_CN
    f=json
    ajax=1
    请求方式:
    GET
    在这个接口中我们需要获取的值有上一步的token以及fakeid,而这个fakeid则在第一个接口中可以获取得到。从而我们就可以拿到微信公众号文章的数据了。
    微信公众号

    三.实现

    第一步:

    首先我们需要通过selenium模拟登录,然后获取到cookie和对应的token

    def weChat_login(user, password):
        post = {}
        browser = webdriver.Chrome()
        browser.get('https://mp.weixin.qq.com/')
        sleep(3)
        browser.delete_all_cookies()
        sleep(2)
        # 点击切换到账号密码输入
        browser.find_element_by_xpath("//a[@class='login__type__container__select-type']").click()
        sleep(2)
        # 模拟用户点击
        input_user = browser.find_element_by_xpath("//input[@name='account']")
        input_user.send_keys(user)
        input_password = browser.find_element_by_xpath("//input[@name='password']")
        input_password.send_keys(password)
        sleep(2)
        # 点击登录
        browser.find_element_by_xpath("//a[@class='btn_login']").click()
        sleep(2)
        # 微信登录验证
        print('请扫描二维码')
        sleep(20)
        # 刷新当前网页
        browser.get('https://mp.weixin.qq.com/')
        sleep(5)
        # 获取当前网页链接
        url = browser.current_url
        # 获取当前cookie
        cookies = browser.get_cookies()
        for item in cookies:
            post[item['name']] = item['value']
        # 转换为字符串
        cookie_str = json.dumps(post)
        # 存储到本地
        with open('cookie.txt', 'w+', encoding='utf-8') as f:
            f.write(cookie_str)
        print('cookie保存到本地成功')
        # 对当前网页链接进行切片,获取到token
        paramList = url.strip().split('?')[1].split('&')
        # 定义一个字典存储数据
        paramdict = {}
        for item in paramList:
            paramdict[item.split('=')[0]] = item.split('=')[1]
        # 返回token
        return paramdict['token']
    

    定义了一个登录方法,里面的参数为登录的账号和密码,然后定义了一个字典用来存储cookie的值。通过模拟用户输入对应的账号密码并且点击登录,然后会出现一个扫码验证,用登录的微信去扫码即可。
    刷新当前网页后,获取当前cookie以及token然后返回。

    第二步:

    1.请求获取对应公众号接口,取到我们需要的fakeid

        url = 'https://mp.weixin.qq.com'
        headers = {
            'HOST': 'mp.weixin.qq.com',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36 Edg/86.0.622.63'
        }
        with open('cookie.txt', 'r', encoding='utf-8') as f:
            cookie = f.read()
        cookies = json.loads(cookie)
        resp = requests.get(url=url, headers=headers, cookies=cookies)
        search_url = 'https://mp.weixin.qq.com/cgi-bin/searchbiz?'
        params = {
            'action': 'search_biz',
            'begin': '0',
            'count': '5',
            'query': '搜索的公众号名称',
            'token': token,
            'lang': 'zh_CN',
            'f': 'json',
            'ajax': '1'
        }
        search_resp = requests.get(url=search_url, cookies=cookies, headers=headers, params=params)
    

    将我们获取到的token和cookie传进来,然后通过requests.get请求,获得返回的微信公众号的json数据

    lists = search_resp.json().get('list')[0]
    

    通过上面的代码即可获取到对应的公众号数据

    fakeid = lists.get('fakeid')
    

    通过上面的代码就可以得到对应的fakeid

    2.请求获取微信公众号文章接口,取到我们需要的文章数据

        appmsg_url = 'https://mp.weixin.qq.com/cgi-bin/appmsg?'
        params_data = {
            'action': 'list_ex',
            'begin': '0',
            'count': '5',
            'fakeid': fakeid,
            'type': '9',
            'query': '',
            'token': token,
            'lang': 'zh_CN',
            'f': 'json',
            'ajax': '1'
        }
        appmsg_resp = requests.get(url=appmsg_url, cookies=cookies, headers=headers, params=params_data)
    

    我们传入fakeid和token然后还是调用requests.get请求接口,获得返回的json数据。
    我们就实现了对微信公众号文章的爬取。

    四.总结

    通过对微信公众号文章的爬取,需要掌握selenium和requests的用法,以及如何获取到请求接口。但是需要注意的是当我们循环获取文章时,一定要设置延迟时间,不然账号很容易被封禁,从而得不到返回的数据。

    展开全文
  • 微信公众号爬虫.rar

    2019-12-20 16:30:58
    微信公众号完成爬虫,内附整个项目的详细教程和所需相关配置软件,按照教程简单配置即可使用该项目为python的项目,新手小白也可轻松使用
  • 基于搜狗微信搜索的微信公众号爬虫 可以抓取指定公众号的文章信息到mysql数据库。对sogo和微信验证码,调用ruokuai接口进行识别。 项目使用: 一、使用说明 1、在mysql数据库中创建数据库,sql语句见gongzhonghao....
  • 基于node的微信公众号爬虫插件 #使用说明 test.js为启动文件 在cmd通过node test.js 命令启动 #介绍 非常简单的微信公众号爬虫功能。 1、通过搜狗微信搜索公众号,获取第一个公众号信息(例如python) 2、进入公众号...
  • 微信公众号爬虫weixin_crawler开源啦 正式介绍weixin_crawler之前,我准备了两个问题,这两个问题通过weixin_crawler自带的报告和搜索指数都能得到回答。 题1:高考在每年的几月举行? 有无数种方法可以...
  • 由于微信公众号爬虫的特殊性,微信公众号爬虫始终是爬虫工程师比较头疼的一个问题。 本文主要介绍一下目前市面上各种爬虫的优劣性以及适用群体 如果您有任何不同见解,或者除文中四种方式之外的方式.欢迎留言跟我...
  • GitHub 微信公众号爬虫推荐 本文推荐 GitHub 微信公众号爬虫article_spider 。 微信公众号爬虫有别于一般的网页爬虫,由于是一个相对封闭的内容平台,入口比较少,所以难度就有点大了。大概查找了一下,发觉基本上不...
  • 需求 某某微信公众号历史的所有文章的阅读数和点赞数 难点 微信公众号历史的所有文章(来源???) 每篇文章的阅读量和点赞量(电脑上浏览文章只显示内容,没有阅读量、点赞量、评论……) 突破难点一 搜狗微信...
  • python微信公众号开发

    2018-10-24 09:54:03
    微信公众号的开发,暂时只做了一个简单的菜单,一个天气查询,用到了最简单的爬虫
  • 快速搭建一个基于《搜狗微信公众号》的微信公众号爬虫教程,教你分分钟爬取微信公众号文章
  • 之前写过一篇类似的...谢谢主要功能如何简单爬虫微信公众号获取信息:标题、摘要、封面、文章地址自动批量下载公众号内的视频本次选取的公众号:熊孩子与萌宠每天更新视频:熊孩子日常、萌宠日常、熊孩子和萌宠搞...
  • Python 微信公众号 小程序爬虫

    万次阅读 2021-05-17 22:37:27
    解决:请在微信客户端打开链接 谷歌浏览器设置 1.F12–ctrl shift p 打开命令框–搜索 network conditions– 2.找到下面的 User Agent,取消选择 Select automatically (自动选择) 3.然后在下面的输入框中加入“ ...
  • 微信公众号爬虫 主要通过搜狗微信进行文章搜索,然后依次模拟浏览获取文章网页源码(主要搜狗微信有反爬虫机制,这是我认为唯一可行的办法),通过pdfkit存到本地,每一篇文章大概需要2-4分钟,公众号文章较多的话...
  • hello,小伙伴们,大家好,今天给大家分享的开源项目是微信公众号爬虫,感兴趣的朋友可以参考一下这个开源项目,看看是否可以给你提供一个新的思路。 项目简介 基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成...
  • 在网站搜索微信公众号爬虫,大多是Python写的,经过几个研究,我用c++也写了基本功能! 爬几千条后会显示访问频繁,接下来将通过代理IP来测试 !有共同的爱好欢迎一起讨论! 交流群 1503118521005923608。 ...
  • 高效微信爬虫,微信公众号爬虫,公众号历史文章,文章评论,文章阅读及在看数据更新,可视化网页,可部署于Windows服务器。 使用环境 基于Python3 ==> flask/mysql/redis/mitmproxy/pywin32等实现 查看及安装依赖...
  • 服务端爬取实现见:微信公众号爬虫:服务端公众号文章数据采集 背景:在团队的学习方面需要每周收集开发方面的博客文章,汇总输出每周的技术周报。周报小组成员收集的文章大多数是来自微信公众号,公众号的内容相对...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,339
精华内容 4,135
关键字:

python微信公众号爬虫

python 订阅
爬虫 订阅