python經過手機抓取微信公衆號

使用 Fiddler 抓包分析公衆號

打開微信隨便選擇一個公衆號,查看公衆號的全部歷史文章列表html

 

 在 Fiddler 上已經能看到有請求進來了,說明公衆號的文章走的都是HTTPS協議,這些請求就是微信客戶端向微信服務器發送的HTTP請求。python

模擬微信請求 android

一、服務器的響應結果,200 表示服務器對該請求響應成功
二、請求協議,微信的請求協議都是基 於HTTPS 的,因此Fiddle必定要配置好,否則你看不到 HTTPS 的請求。
三、請求路徑,包括了請求方法(GET),請求協議(HTTP/1.1),請求路徑(/mp/profile_ext...後面還有很長一串參數)web

四、包括Cookie信息在內的請求頭。json

五、微信服務器返回的響應數據。數組

 

肯定微信公衆號的請求HOST是 mp.weixin.qq.com 以後,咱們可使用過濾器來過濾掉不相關的請求。瀏覽器

爬蟲的基本原理就是模擬瀏覽器發送 HTTP 請求,而後從服務器獲得響應結果,如今咱們就用 Python 實現如何發送一個 HTTP 請求。這裏咱們使用 requests 庫來發送請求。服務器

拷貝URL和請求頭

  • 1:找到完整URL請求地址
  • 2:找到完整的請求頭(headers)信息,Headers裏面包括了cookie、User-agent、Host 等信息。

咱們直接從 Fiddler 請求中拷貝 URL 和 Headers, 右鍵 -> Copy -> Just Url/Headers Only微信

 

url = 'https://mp.weixin.qq.com/mp/profile_ext' \
      '?action=home' \
      '&__biz=MzA5MTAxMjEyMQ==' \
      '&scene=126' \
      '&bizpsid=0' \
      '&devicetype=android-23' \
      '&version=2607033c' \
      '&lang=zh_CN' \
      '&nettype=WIFI' \
      '&a8scene=3' \
      '&pass_ticket=LvcLsR1hhcMXdxkZjCN49DcQiOsCdoeZdyaQP3m5rwXkXVN7Os2r9sekOOQULUpL' \
      '&wx_header=1'

  

由於 requests.get 方法裏面的 headers 參數必須是字典對象,因此,先要寫個函數把剛剛拷貝的字符串轉換成字典對象。cookie

def headers_to_dict(headers):
    """
    將字符串
    '''
    Host: mp.weixin.qq.com
    Connection: keep-alive
    Cache-Control: max-age=
    '''
    轉換成字典對象
    {
        "Host": "mp.weixin.qq.com",
        "Connection": "keep-alive",
        "Cache-Control":"max-age="
    }
    :param headers: str
    :return: dict
    """
    headers = headers.split("\n")
    d_headers = dict()
    for h in headers:
        if h:
            k, v = h.split(":", 1)
            d_headers[k] = v.strip()
    return d_headers

公衆號歷史文章數據就在 response.text 中。若是返回的內容很是短,並且title標籤是<title>驗證</title>,

那麼說明你的請求參數或者請求頭有誤,最有可能的一種請求就是 Headers 裏面的 Cookie 字段過時,

從手機微信端從新發起一次請求獲取最新的請求參數和請求頭試試

 response = requests.get(url, headers=headers_to_dict(headers), verify=False)
    print(response.text)
    if '<title>驗證</title>' in response.text:
        raise Exception("獲取微信公衆號文章失敗,多是由於你的請求參數有誤,請從新獲取")
# with open("weixin_history.html", "w", encoding="utf-8") as f:
#     f.write(response.text)

歷史文章封裝在叫 msgList 的數組中(實際上該數組包裝在字典結構中),這是一個 Json 格式的數據,可是裏面還有 html 轉義字符須要處理

 

寫一個方法提取出歷史文章數據,分三個步驟,首先用正則提取數據內容,而後 html 轉義處理,最終獲得一個列表對象,返回最近發佈的10篇文章

def extract_data(html_content):
    """
    從html頁面中提取歷史文章數據
    :param html_content 頁面源代碼
    :return: 歷史文章列表
    """
    import re
    import html
    import json

    rex = "msgList = '({.*?})'"  # 正則表達
    pattern = re.compile(pattern=rex, flags=re.S)
    match = pattern.search(html_content)
    if match:
        data = match.group(1)
        data = html.unescape(data)  # 處理轉義
        # print('data: {}'.format(data))
        data = json.loads(data)
        articles = data.get("list")
        for item in articles:
            print(item)
        return articles

 

最終提取出來的數據總共有10條,就是最近發表的10條數據,咱們看看每條數據返回有哪些字段。

 

發送時間對應comm_msg_info.datetime,app_msg_ext_info中的字段信息就是第一篇文章的字段信息,分別對應:

  • title:文章標題
  • content_url:文章連接
  • source_url:原文連接,有可能爲空
  • digest:摘要
  • cover:封面圖
  • datetime:推送時間

後面幾篇文章以列表的形式保存在 multi_app_msg_item_list 字段中。

 

 

 詳細代碼

import requests

url = 'https://mp.weixin.qq.com/mp/profile_ext' \
      '?action=home' \
      '&__biz=MzA5MTAxMjEyMQ==' \
      '&scene=126' \
      '&bizpsid=0' \
      '&devicetype=android-23' \
      '&version=2607033c' \
      '&lang=zh_CN' \
      '&nettype=WIFI' \
      '&a8scene=3' \
      '&pass_ticket=LvcLsR1hhcMXdxkZjCN49DcQiOsCdoeZdyaQP3m5rwXkXVN7Os2r9sekOOQULUpL' \
      '&wx_header=1'


headers ='''
Host: mp.weixin.qq.com

Connection: keep-alive

User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; OPPO R9s Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044405 Mobile Safari/537.36 MMWEBID/5576 MicroMessenger/6.7.3.1360(0x2607033C) NetType/WIFI Language/zh_CN Process/toolsmp

x-wechat-key: d2bc6fe213fd0db717e11807caca969ba1d7537e57fc89f64500a774dba05a4f1a83ae58a3d039efc6403b3fa70ebafb52cfd737b350b58d0dca366b5daf92027aaefcb094932df5a18c8764e98703dc

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

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

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.7.3&TBSVC=43620&CO=BK&COVC=044405&PB=GE&VE=GA&DE=PHONE&CHID=0&LCID=9422&MO= OPPOR9s &RL=1080*1920&OS=6.0.1&API=23

Q-GUID: edb298c301f35e6c59298f2313b788cb

Q-Auth: 31045b957cf33acf31e40be2f3e71c5217597676a9729f1b
'''


def headers_to_dict(headers):
    """
    將字符串
    '''
    Host: mp.weixin.qq.com
    Connection: keep-alive
    Cache-Control: max-age=
    '''
    轉換成字典對象
    {
        "Host": "mp.weixin.qq.com",
        "Connection": "keep-alive",
        "Cache-Control":"max-age="
    }
    :param headers: str
    :return: dict
    """
    headers = headers.split("\n")
    d_headers = dict()
    for h in headers:
        if h:
            k, v = h.split(":", 1)
            d_headers[k] = v.strip()
    return d_headers


# with open("weixin_history.html", "w", encoding="utf-8") as f:
#     f.write(response.text)


def extract_data(html_content):
    """
    從html頁面中提取歷史文章數據
    :param html_content 頁面源代碼
    :return: 歷史文章列表
    """
    import re
    import html
    import json

    rex = "msgList = '({.*?})'"  # 正則表達
    pattern = re.compile(pattern=rex, flags=re.S)
    match = pattern.search(html_content)
    if match:
        data = match.group(1)
        data = html.unescape(data)  # 處理轉義
        # print('data: {}'.format(data))
        data = json.loads(data)
        articles = data.get("list")

        return articles


def crawl():
    """
     爬取文章
    :return:
    """
    response = requests.get(url, headers=headers_to_dict(headers), verify=False)
    print(response.text)
    if '<title>驗證</title>' in response.text:
        raise Exception("獲取微信公衆號文章失敗,多是由於你的請求參數有誤,請從新獲取")
    data = extract_data(response.text)
    for item in data:
        print(item['app_msg_ext_info'])

if __name__ == '__main__':
    crawl()
相關文章
相關標籤/搜索