微信公众号文章爬虫

作者: Evtion | 来源:发表于2017-10-15 14:37 被阅读1717次

    很多的微信公众号都提供了质量比较高的文章阅读,对于自己喜欢的微信公众号,所以想做个微信公众号爬虫,爬取相关公众号的所有文章。抓取公众号的所有的文章,需要获取两个比较重要的参数。一个是微信公众号的唯一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_=
      
      • 下面是搜索的结果页面:
    搜索结果
    • 查看源代码,可以发现每一个公众号的链接,都是位于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值:
    只有10条文章达不到要求
     //其中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";
    
      1. 获取到微信公众号的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
      
      • 获取到公众号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)
      
    获取的wap_sid2和__biz值
    • 在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")
    
    • 获取到的数据如下图所示:
    最终捕获的数据
    • 在爬取的过程中,有时候经过抓包,想获取一个重定向的网页的响应头;但是响应头cookies已经设置read only,我们想通过这里获取权限值,可以通过设置Fiddler的rules来生成保存响应文件。在微信文章爬取过程中,虽然也是想通过这种方式获取权限值。但是发觉自己是忽略了请求头x-wechat-key和x-wechat-uin所以获取不到。所以这种方式在该项目并不需要。但是提供一种获取动态设置cookies值,然后重定向到新页面的响应头方法,比如获取 https://mp.weixin.qq.com/mp/profile_ext?action=home
      查看FiddlerScript
    • 在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";
          }
      }
    
    响应头 哈哈

    源代码的readme.md文件介绍使用的方式,需要可以直接到github上面获取源码,github源码地址;喜欢的给个star哟。
    其他类似文章

    相关文章

      网友评论

      • d58b8ba4a9dc:现在的x-wechat-key是不无法跨公众号使用了?
      • d58b8ba4a9dc:您好,我想抓取到wap_sid2的值,我将参数替换发送请求,获取成功了,我把header打印出来,但是header里除了想要的set-cookie值其它都有,我应该去哪找想要的set-cookie
        d58b8ba4a9dc:@Evtion 大神,我看你一个x-wehchat-key就可以获得多个公众号的wap_sid2,但是我把请求中的biz一换以后就得换对应公众号的x-wechat-key,这是为什么呢?
        Evtion:@心匠盒子 登录你的账号来获取
      • 6777783dbbf1:您好,请问x-wechat-key值是怎么获取的?
        Evtion:@shijingjing07 可以通过手机抓包

      本文标题:微信公众号文章爬虫

      本文链接:https://www.haomeiwen.com/subject/zybiyxtx.html