使用Python快速獲取公眾號文章定製電子書(一)

WeaponZhi發表於2018-05-23

原文連結

我的GitHub部落格地址

前言

分享一個筆者最近寫的 Python 相關的小 demo,爬取某個公眾號的所有歷史文章,並匯出到本地,方便之後線上下環境直接觀看。參考了劉志軍的小冊基於Python實現微信公眾號爬蟲,有興趣的同學也可以自行購買。

這個功能還是有一定實際用途的,需求和功能雖然簡單明確,但我在開發的過程中,也是遇到了一定的問題,可以說好好的把 Python 爬蟲方面的知識複習了一遍。我也將從最基礎的抓包開始講起,希望能提供一個完整爬取流程的簡單教程。

抓包

在 Windows 平臺,我們經常使用 Fiddler 來進行抓包,筆者使用 Mac,所以比較習慣使用 Charles 來進行抓包。不僅如此,這類工具在開發過程中是非常重要的工具,筆者平時在客戶端開發過程中,如果服務端介面還沒完成,只要定義好資料結構,通過這類工具的重定向功能,就可以輕易的自己模擬資料來開發了。

用手機抓取 https 介面,需要在手機裡安裝證照,網上方法很多,我這裡就不費篇幅了。

我們開啟微信歷史訊息介面,然後在 Charles 裡面找尋介面,通過觀察 Response 返回的內容,我們發現了我們需要的請求:

使用Python快速獲取公眾號文章定製電子書(一)

第一頁爬取

我們在 Python 中記錄下這個 url 和 Header,需要注意的是,這個url請求的資料只是第一頁的資料,上拉載入的url介面形式是完全不同的。

 url = "https://mp.weixin.qq.com/mp/profile_ext?" \
          "action=home&" \
          "__biz=MjM5ODIyMTE0MA==&" \
          "scene=124&" \
          "devicetype=android-23&" \
          "version=26060532&" \
          "lang=zh_CN&" \
          "nettype=WIFI&" \
          "a8scene=3&" \
          "pass_ticket=Pu%2FH3aPR7f%2FzgA52T%2Bv4fU9wSWkY5tgGGgAXWewji2dqpMDrjaxUbBR%2Fmo2e%2FaMX&wx_header=1"

headers = """
Host: mp.weixin.qq.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; NX531J Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/044030 Mobile Safari/537.36 MicroMessenger/6.6.5.1280(0x26060532) NetType/WIFI Language/zh_CN
x-wechat-key: b97b0a94956e0cb26093b03bcbfb059796e335db8c12a8036cdff0191103874cee2a5045062b4058d71c848ab74c8b256570c9a9547fe2eb9572b1a762f9cea43f91428b4a31bf5618a8c61c00da7287
x-wechat-uin: MTMzNjE3ODYyMQ%3D%3D
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,image/wxpic,image/sharpp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,en-US;q=0.8
Cookie: sd_userid=96301522585723838; sd_cookie_crttime=1522585723838; pgv_pvid=1151171120; tvfe_boss_uuid=92a513a6354c3896; rewardsn=; wxtokenkey=777; wxuin=1336178621; devicetype=android-23; version=26060532; lang=zh_CN; pass_ticket=Pu/H3aPR7f/zgA52T+v4fU9wSWkY5tgGGgAXWewji2dqpMDrjaxUbBR/mo2e/aMX; wap_sid2=CL3vkf0EEnBSWHFYWmVoZVpOMjU0cnBpSUhiLWF2cmZHVVVLVWZrWUp4QVRlclVVOTRwS1hmMGNUR0VJaXp1RlVzbGViM2wtZnVfakZVd21RcGxxbzI3U3R3cmtYYlUycXpLU0FzcGJFSm1ESkZsYVhzSzhBd0FBMLbQ5dcFOA1AlU4=
Q-UA2: QV=3&PL=ADR&PR=WX&PP=com.tencent.mm&PPVN=6.6.5&TBSVC=43603&CO=BK&COVC=044030&PB=GE&VE=GA&DE=PHONE&CHID=0&LCID=9422&MO= NX531J &RL=1080*1920&OS=6.0.1&API=23
Q-GUID: 6a875f18ea5ba76bb6afb9ca13b788cb
Q-Auth: 31045b957cf33acf31e40be2f3e71c5217597676a9729f1b
"""
複製程式碼

這個請求返回的是一個 H5 介面,並不是我們期望的是一個 JSON 檔案,但沒關係,通過我們的 xml 解析器,我們始終可以通過細緻的觀察,找尋我們需要的資訊。我們發現,下面這段程式碼,隱藏著前十條文章的資料列表。

使用Python快速獲取公眾號文章定製電子書(一)

def extract_data(html_content):
   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)
       data = json.loads(data)
       articles = data.get("list")
       articles_lists = dict()
       for item in articles:
           if item.get("app_msg_ext_info"):
               articles_lists[item["app_msg_ext_info"]["title"]] = item["app_msg_ext_info"]["content_url"]
       return articles_lists
複製程式碼

我們可以通過正則來提取出這部分資料,儲存在 json 中,現在讓我們來分析下資料:

article = {'app_msg_ext_info': 
               {'title': '那些對印度的誤解與偏見',
                'copyright_stat': 11,
                'is_multi': 1,
                'content': '',
                'author': 'WeaponZhi',
                'subtype': 9,
                'del_flag': 1,
                'fileid': ,
                'content_url': 'http:\\/\\/mp....',
                ''
                'digest': '提到印度,你首先會想到什麼',
                'cover': 'http:\\/\\/mmbiz.qpic.cn\\...',
                'multi_app_msg_item_list': [{'fileid': 861719336,
                                             'content_url': 'http:\\/\\/mp...',
                                             'content': '', 'copyright_stat': 11,
                                             'cover': 'http:\\/\\/mmbiz.qpic.cn',
                                             'del_flag': 1,
                                             'digest': '攜程再努努力就快趕上百度了',
                                             '...
複製程式碼

根據我們歷史文章的樣式,以及我們需要的資料和需求,筆者抽取了每篇文章的幾個重要欄位:

  • title:文章標題
  • content_url:文章連結
  • digest:摘要
  • multi_app_msg_item_list:同時傳送的其他文章的欄位列表

multi_app_msg_item_list 欄位就是一組多圖文資料列表,在微信裡的展現形式是這樣的

使用Python快速獲取公眾號文章定製電子書(一)

現在我們拿到了每篇文章的具體連結 content_url,後面我們需要做的就是請求這個url,從中抽取文章內容,再把內容以一定的格式儲存在檔案中即可。

headers = headers_to_dict(headers)
response = requests.get(url, headers=headers, verify=False)
if '<title>驗證</title>' in response.text:
   raise Exception("獲取微信公眾號文章失敗,可能是因為你的請求引數有誤,請重新獲取")
data = extract_data(response.text)
rex = r'\\/'
for item in data:
   pattern = re.sub(rex, '/', html.unescape(data.get(item)))
   response = requests.get(pattern, headers=headers, verify=False)
   parser_text_to_file(item, response.text)

def parser_text_to_file(title, article_content):
   soup = BeautifulSoup(article_content, 'html.parser', from_encoding='utf8')
   node = soup.find(id="js_content")
   write_text_to_file(title, node)


def write_text_to_file(title, node):
   contents = node.descendants
   for item in contents:
       if isinstance(item, NavigableString):
           with open(title, "a", encoding="utf-8") as f:
               f.write(str(item))
               f.write('\n\n')
複製程式碼

這裡我們寫了一個驗證判斷,為了防止過度的爬取操作,爬取歷史文章的介面 Cookie 只能有一定的有效時間,如果你在爬取過程中發現獲取資料失敗,那你就需要重新進入介面然後更新程式碼中的 Header 中的Cookie了,我們在後面的文章中對這個問題將進行具體解析。

實際上上面的程式碼就是這個小 demo 的業務核心了,我們現在只處理了歷史文章前十篇的內容,下篇文章我將通過載入更多介面,將一個公眾號所有文章爬取出來,更有意思的自然還在後面。


推薦閱讀

機器學習股票價格預測從爬蟲到預測-預測與調參

機器學習股票價格預測初級實戰

機器學習股票價格預測從爬蟲到預測(資料爬取部分)

關注公眾號獲取更多幹貨文章-AI極客研修站

使用Python快速獲取公眾號文章定製電子書(一)

相關文章