• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • Python:使用 MitmProxy 自動抓取微信公眾號閱讀數、點贊和再看數據

    標簽: Python爬蟲  python  爬蟲

    前言

    本文的文字及圖片來源于網絡,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯系我們以作處理。

    作者:某某白米飯

    PS:如有需要Python學習資料的小伙伴可以加點擊下方鏈接自行獲取

    python學習交流群,點擊即可加入本群

    某天接到一個需要抓取某某微信公眾的所有歷史文章的閱讀數、點贊和再看數據的需求。

    為了解放雙手,就用 Python 代碼擼一個,選擇 MitmProxy 代理作為抓包工具,因為它可以使用 Python 代碼監聽抓取到的 url,用于自動獲取 cookie 等場景。

    什么是 MitmProxy

    mitmproxy 是一個支持 HTTP 和 HTTPS 的抓包程序,有類似 Fiddler 的功能。

    mitmproxy 還有兩個關聯組件。一個是 mitmdumvp,它是 mitmproxyv 的命令行接口,可以利用 Python 代碼監聽請求。另一個是 mitmweb,它是一個 Web 程序,可以觀察 mitmproxy 抓取的請求。

    安裝和設置

    使用 pip 安裝

    pip install mitmproxy
    

    安裝好之后,將手機端的代理 IP 設置為和 PC 的 IP 地址一樣,和代理端口設置為:8080,用下面命令啟動

    mitmweb
    

    將看到瀏覽器打開了一個 http://127.0.0.1:8081/#/flows 網頁,這個就是 MitmProxy 的 web 控制臺
    在這里插入圖片描述
    在手機端瀏覽器輸入 mitm.im 獲取 PC 證書 和手機端的證書,都安裝一下
    在這里插入圖片描述
    注意:android 手機在安裝證書時需要在[從存儲設備安裝]界面安裝

    閱讀數、再看、點贊抓取

    當安裝好證書和設置好手機端 IP 代理后,隨便點擊一篇微信公眾號文章(這里使用本公眾)
    在這里插入圖片描述
    從圖上可以看到,閱讀、再看、點贊的 url 為 https://mp .weixin. qq. com/mp/getappmsgext(提示:如果沒有這個鏈接,可以右上角刷新文章),再看下它的 request 請求需要哪些東西
    在這里插入圖片描述
    在這里插入圖片描述
    只需要一個文章 url、user-agent、cookie 和 body 這四個基本的數據,別看下面 body 里面有二三十個數據其實都是嚇唬人的,只需要其中7個,分別是 __biz, mid, idx,sn 這四個參數是獲取公眾號文章內容的基石,可以在文章 url 處獲得。其他三個參數的數據是固定的分別是 is_only_read = 1,is_temp_url = 0,appmsg_type = 9。getappmsgext 請求中的 appmsg_token 是一個有時效性的參數。

    分析完鏈接后就可以寫代碼了

    import html
    import requests
    import utils
    
    from urllib.parse import urlsplit
    
    class Articles(object):
        """文章信息"""
    
        def __init__(self, appmsg_token, cookie):
            # 具有時效性
            self.appmsg_token = appmsg_token
            
            self.headers = {
                "User-Agent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0Chrome/57.0.2987.132 MQQBrowser/6.2 Mobile""Cookie": cookie
            }
            
            self.data = {
                "is_only_read": "1""is_temp_url": "0""appmsg_type": "9"}
    
    
        def read_like_nums(self, article_url):
            """獲取數據"""
            appmsgstat = self.get_appmsgext(article_url)["appmsgstat"]
            return appmsgstat["read_num"], appmsgstat["old_like_num"], appmsgstat["like_num"]
    
        def get_params(self, article_url):
            """
            獲取到文章url上的請求參數
            :param article_url: 文章 url
            :return: 
            """
            # url轉義處理
            article_url = html.unescape(article_url)
            """獲取文章鏈接的參數"""
            url_params = utils.str_to_dict(urlsplit(article_url).query, "&""=")
            return url_params
    
        def get_appmsgext(self, article_url):
            """
            請求閱讀數
            :param article_url: 文章 url
            :return: 
            """
            url_params = self.get_params(article_url)
    
            appmsgext_url = "https://mp. weixin.qq.com/mp/getappmsgext?appmsg_token={}&x5=0".format(self.appmsg_token)
            self.data.update(url_params)
    
            appmsgext_json = requests.post(
                appmsgext_url, headers=self.headers, data=self.data).json()
    
            if "appmsgstat" not in appmsgext_json.keys():
                raise Exception(appmsgext_json)
            return appmsgext_json
    
    
    if __name__ == '__main__':
        info = Articles('1068_XQoMoGGBYG8Tf8k23jfdBr2H_LNekAAlDDUe2aG13TN2fer8xOSMyrLV6s-yWESt8qg5I2fJr1r9n5Y5''rewardsn=; wxtokenkey=777; wxuin=1681274216; devicetype=android-29; version=27001037; lang=zh_CN; pass_ticket=H9Osk2CMhrlH34mQ3w2PLv/RAVoiDxweAdyGh/Woa1qwGy2jGATJ6hhg7syTQ9nk; wap_sid2=COjq2KEGEnBPTHRVOHlYV2U4dnRqaWZqRXBqaWl3Xy1saXVWYllIVjAzdlM1VkNDNHgxeWpHOG9pckdkREMwTFEwYmNWMl9FZWtRU3pRRnhDS0pyV1BaZUVMWXN1ZWN0WnZ6aHFXdVBnbVhTY21BYnBSUXNCQUFBMLLAjfgFOA1AAQ==')
        a, b,c = info.read_like_nums('http://mp. weixin.qq.com/s?__biz=MzU1NDk2MzQyNg==&amp;mid=2247486254&amp;idx=1&amp;sn=c3a47f4bf72b1ca85c99190597e0c190&amp;chksm=fbdad3a3ccad5ab55f6ef1f4d5b8f97887b4a344c67f9186d5802a209693de582aac6429a91c&amp;scene=27#wechat_redirect')
        print(a, b, c)
    

    示例結果

    # 閱讀數 點贊數 再看數
    1561 23 18
    

    動態獲取 cookie 和 appmsg_token

    appmsg_token 是一個具有時效性的參數,和 cookie 一樣是需要改變的,當這兩個參數過期時就需要從抓包工具(MitmProxy 中)ctrl+C,ctrl+V到代碼中,很是麻煩。

    MitmProxy 可以使用命令行接口 mitmdumvp 運行 Python 代碼監聽抓取的鏈接,如果抓到了 https://mp. weixin.qq.com/mp/getappmsgext 就保存在本地文件并退出抓包

    mitmdump 命令

    # -s 運行的python腳本, -w 將截取的內容保持到文件
    mitmdump -s write_cookie.py -w outfile mp.weixin.qq.com/mp/getappmsgext
    

    監聽腳本

    import urllib
    import sys
    
    from mitmproxy import http
    
    # command: mitmdump -s write_cookie.py -w outfile mp.weixin.qq.com/mp/getappmsgext
    
    class WriterCookie:
        """
        mitmproxy的監聽腳本,寫入cookie和url到文件
        """
    
        def __init__(self, outfile: str) -> None:
            self.f = open(outfile, "w")
    
        def response(self, flow: http.HTTPFlow) -> None:
            """
            完整的response響應
            :param flow: flow實例,
            """
            # 獲取url
            url = urllib.parse.unquote(flow.request.url)
    
            # 將url和cookie寫入文件
            if "mp. weixin.qq.com/mp/getappmsgext" in url:
                self.f.write(url + '\n')
                self.f.write(str(flow.request.cookies))
                self.f.close()
                # 退出
                exit()
    
    # 第四個命令中的參數
    addons = [WriterCookie(sys.argv[4])]
    

    監聽腳本寫好之后,再來寫啟動命令和解析 url,cookie 文件的模塊

    import re
    import os
    
    class ReadCookie(object):
        """
        啟動write_cookie.py 和 解析cookie文件,
        """
    
        def __init__(self, outfile):
            self.outfile = outfile
    
        def parse_cookie(self):
            """
            解析cookie
            :return: appmsg_token, biz, cookie_str·
            """
            f = open(self.outfile)
            lines = f.readlines()
            appmsg_token_string = re.findall("appmsg_token.+?&", lines[0])
            biz_string = re.findall('__biz.+?&', lines[0])
            appmsg_token = appmsg_token_string[0].split("=")[1][:-1]
            biz = biz_string[0].split("__biz=")[1][:-1]
    
            cookie_str = '; '.join(lines[1][15:-2].split('], [')).replace('\'''').replace(', ''=')
            return appmsg_token, biz, cookie_str
    
        def write_cookie(self):
            """
            啟動 write_cookie。py
            :return:
            """
    
            #當前文件路徑
            path = os.path.split(os.path.realpath(__file__))[0]
            # mitmdump -s 執行腳本 -w 保存到文件 本命令
            command = "mitmdump -s {}/write_cookie.py -w {} mp.weixin.qq.com/mp/getappmsgext".format(
                path, self.outfile)
    
            os.system(command)
    
    
    if __name__ == '__main__':
        rc = ReadCookie('cookie.txt')
        rc.write_cookie()
        appmsg_token, biz, cookie_str = rc.parse_cookie()
        print("appmsg_token:" + appmsg_token , "\nbiz:" + biz, "\ncookie:"+cookie_str)
    

    示例結果
    在這里插入圖片描述
    cookie.txt 文件內容解析后

    appmsg_token:1068_av3JWyDn2XCS2fwFj3ICCnwArRb2kU4Y5Y5m9Z9NkWoCOszl3a-YHFfBkAguUlYQJi2dWo83AQT4FsNK 
    biz:MzU1NDk2MzQyNg== 
    cookie:rewardsn=; wxtokenkey=777; wxuin=1681274216; devicetype=android-29; version=27001037; lang=zh_CN; pass_ticket=H9Osk2CMhrlH34mQ3w2PLv/RAVoiDxweAdyGh/Woa1qwGy2jGATJ6hhg7syTQ9nk; wap_sid2=COjq2KEGEnBPTHRVOHlYV2U4dnRqaWZqRXBqaWktTHpUSEJnTTdhU0hVZTEtZXpZZEY4a3lNY29zc0VZeEFvLS01YmJRRnQ5eFRmR2dOY29nUWdKSTRVWG13WE1obGs1blhQcVh0V18tRnBSRnVlc1VhOHNCQUFBMPeIjfgFOA1AAQ==
    

    ReadCookie 模塊可以自動獲取到 appmsg_token 和 cookie,將它們當作參數一樣傳遞到 Articles 模塊中,就能解放雙手再也不要復制黏貼 appmsg_token 和 cookie 了,只要在 appmsg_token 過期時刷新一下公眾號文章就可以了,省心又省時

    批量抓取

    在公眾號歷史消息界面將屏幕向上滑動,每次都可以加載 10 條歷史消息,盲猜這個翻頁就是批量抓取的請求鏈接,用 MitmProxy 的 WEBUI 界面在 Response 面板查找一下,找到一個是 https://mp. weixin.qq.com/mp/profile_ext?action=getmsg&__biz=MzU1NDk2MzQyNg==&f=json&offset=10&count=10… 的鏈接,它的響應返回值中有多個文章標題,再看這個鏈接上有 offset=10&count=10 參數,一看就是翻頁偏移量和每頁顯示的條數,就它了
    在這里插入圖片描述
    在鏈接中比較重要的參數有:__biz、offset、pass_ticket、appmsg_token ,這些數據都可以在 cookie 和 appmsg_token 中得到。

    # utils.py
    # 工具模塊,將字符串變成字典
    def str_to_dict(s, join_symbol="\n", split_symbol=":"):
        s_list = s.split(join_symbol)
        data = dict()
        for item in s_list:
            item = item.strip()
            if item:
                k, v = item.split(split_symbol, 1)
                data[k] = v.strip()
        return data
    
    import os
    import requests
    import json
    import urllib3
    import utils
    
    
    class WxCrawler(object):
        """翻頁內容抓取"""
        urllib3.disable_warnings()
    
        def __init__(self, appmsg_token, biz, cookie, begin_page_index = 0, end_page_index = 100):
            # 起始頁數
            self.begin_page_index = begin_page_index
            # 結束頁數
            self.end_page_index = end_page_index
            # 抓了多少條了
            self.num = 1
    
            self.appmsg_token = appmsg_token
            self.biz = biz
            self.headers = {
                "User-Agent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0Chrome/57.0.2987.132 MQQBrowser/6.2 Mobile""Cookie": cookie
            }
            self.cookie = cookie
    
        def article_list(self, context):
            articles = json.loads(context).get('general_msg_list')
            return json.loads(articles)
    
        def run(self):
    
            # 翻頁地址
            page_url = "https://mp. weixin.qq.com/mp/profile_ext?action=getmsg&__biz={}&f=json&offset={}&count=10&is_ok=1&scene=&uin=777&key=777&pass_ticket={}&wxtoken=&appmsg_token=" + self.appmsg_token + "&x5=0f=json"
            # 將 cookie 字典化
            wx_dict = utils.str_to_dict(self.cookie, join_symbol='; ', split_symbol='=')
            # 請求地址
            response = requests.get(page_url.format(self.biz, self.begin_page_index * 10, wx_dict['pass_ticket']), headers=self.headers, verify=False)
            # 將文章列表字典化
            articles = self.article_list(response.text)
    
            for a in articles['list']:
                # 公眾號中主條
                if 'app_msg_ext_info' in a.keys() and '' != a.get('app_msg_ext_info').get('content_url'''):
                    print(str(self.num) + "條", a.get('app_msg_ext_info').get('title'), a.get('app_msg_ext_info').get('content_url'))
                # 公眾號中副條
                if 'app_msg_ext_info' in a.keys():
                    for m in a.get('app_msg_ext_info').get('multi_app_msg_item_list'[]):
                        print(str(self.num) + "條", m.get('title'), a.get('content_url'))
    
                self.num = self.num + 1
    
            self.is_exit_or_continue()
            # 遞歸調用
            self.run()
    
        def is_exit_or_continue(self):
            self.begin_page_index = self.begin_page_index + 1
    
            if self.begin_page_index > self.end_page_index:
                os.exit()
    

    最后用自動化cookie啟動程序后刷新公眾號文章

    from read_cookie import ReadCookie
    from wxCrawler import WxCrawler
    
    """程序啟動類"""ss
    if __name__ == '__main__':
        cookie = ReadCookie('E:/python/cookie.txt')
    
        cookie.write_cookie()
        appmsg_token, biz, cookie_str = cookie.parse_cookie()
        wx = WxCrawler(appmsg_token, biz, cookie_str)
        wx.run()
    

    示例結果
    在這里插入圖片描述

    總結

    雖然本文可能有那么一點點一點點的標題黨,并沒有完全的自動抓取數據,還需要人為的刷新一下公眾號文章。希望小伙伴們不要介意哈。

    版權聲明:本文為fei347795790原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/fei347795790/article/details/107284720

    智能推薦

    3D游戲編程與設計——游戲對象與圖形基礎章節作業與練習

    3D游戲編程與設計——游戲對象與圖形基礎章節作業與練習 3D游戲編程與設計——游戲對象與圖形基礎章節作業與練習 自學資源 作業內容 1、基本操作演練【建議做】 天空盒的制作: 地圖的制作: 整體效果: 2、編程實踐 項目要求: 項目結構: 代碼詳解: Actions: ISSActionCallback.cs SSAction.cs SSAction...

    FlycoTabLayout 的使用

    FlycoTabLayout 一個Android TabLayout庫,目前有3個TabLayout SlidingTabLayout:參照PagerSlidingTabStrip進行大量修改. 新增部分屬性 新增支持多種Indicator顯示器 新增支持未讀消息顯示 新增方法for懶癌患者 CommonTabLayout:不同于SlidingTabLayout對ViewPager依賴,它是一個不...

    爬蟲項目實戰八:爬取天氣情況

    爬取天氣情況 目標 項目準備 接口分析 代碼實現 效果顯示 寫入本地 目標 根據天氣接口,爬取接下來一周的天氣情況。 項目準備 軟件:Pycharm 第三方庫:requests,BeautifulSoup,csv 接口地址:http://api.k780.com:88/?app=weather.future&weaid=城市名&appkey=10003&sign=b59bc...

    關于web項目的目錄問題

    先給段代碼: 上面這個代碼一直出錯,我不知道原因,后面不停的查找資料發現了問題:我的web項目輸出目錄有問題,因為我也是第一次用idea寫web項目,發現很多bug 其實都沒有太大問題,我們需要注意的是你必須在out這個輸出文件夾中擁有這個文件,out輸出文件夾會默認過濾這些文件...

    二叉搜索樹轉化為雙向鏈表

    題目描述: 輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的循環雙向鏈表。要求不能創建任何新的節點,只能調整樹中節點指針的指向。 為了讓您更好地理解問題,以下面的二叉搜索樹為例: 我們希望將這個二叉搜索樹轉化為雙向循環鏈表。鏈表中的每個節點都有一個前驅和后繼指針。對于雙向循環鏈表,第一個節點的前驅是最后一個節點,最后一個節點的后繼是第一個節點。 下圖展示了上面的二叉搜索樹轉化成的鏈表。&ldqu...

    猜你喜歡

    Cocos2d-x 2.0 網格動畫深入分析

    [Cocos2d-x相關教程來源于紅孩兒的游戲編程之路CSDN博客地址:http://blog.csdn.net/honghaier] 紅孩兒Cocos2d-X學習園地QQ2群:44208467加群寫:Cocos2d-x 紅孩兒Cocos2d-X學習園地QQ群:249941957[暫滿]加群寫:Cocos2d-x 本章為我的Cocos2d-x教程一書初稿。望各位看官多提建議! Cocos2d-x ...

    vue 子組件傳值父組件 emit

    vue 子組件傳值父組件  emit    ...

    解決Python數據可視化中文部分顯示方塊問題

    一、問題 代碼如下,發現標題的中文顯示的是方塊 如下圖 二、解決方法 一般數據可視化使用matplotlib庫,設置中文字體可以在導入之后添加兩句話(這里的SimHei指的是黑體,KaiTi指的是楷體) 三、效果 1.黑體: 2.楷體: 具體的其他字體可以在matplotlib\mpl-data\fonts\ttf找到~ 四、Windows的常用字體 黑體、楷體、仿宋是可以用的,其他的字體可能需要...

    Linux的LVM掛載(Centos)

    LVM掛載 1、虛擬機添加新增磁盤(如已添加可略過) 2、查看是否有新的硬盤 3、對磁盤分區 4、LVM磁盤創建 參考地址: https://blog.51cto.com/11555417/2158443 1、虛擬機添加新增磁盤(如已添加可略過) 1.點擊虛擬機,選擇硬盤,點擊添加,選擇SCSI硬盤,添加硬盤(如下圖所示)。 2、查看是否有新的硬盤 可以看到 /dev/sdb 是我們新建的磁盤5G...

    Java四大元注解介紹

    Java四大元注解介紹 什么是元注解? 元注解就是注解到注解上的注解。它們被用來提供對其它 annotation類型作說明。 Java5.0定義的元注解: @Retention、@Documented、@Target、@Inherited,這些類型和它們所支持的類在java.lang.annotation包中可以找到。如圖所示: 接下來我們看一下每個元注解的作用和相應分參數的使用說明。 @Docu...

    精品国产乱码久久久久久蜜桃不卡