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

原文連接html

個人GitHub博客地址node

前言

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

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

抓包

在 Windows 平臺,咱們常用 Fiddler 來進行抓包,筆者使用 Mac,因此比較習慣使用 Charles 來進行抓包。不只如此,這類工具在開發過程當中是很是重要的工具,筆者平時在客戶端開發過程當中,若是服務端接口還沒完成,只要定義好數據結構,經過這類工具的重定向功能,就能夠輕易的本身模擬數據來開發了。git

用手機抓取 https 接口,須要在手機裏安裝證書,網上方法不少,我這裏就不費篇幅了。github

咱們打開微信歷史消息界面,而後在 Charles 裏面找尋接口,經過觀察 Response 返回的內容,咱們發現了咱們須要的請求:web

第一頁爬取

咱們在 Python 中記錄下這個 url 和 Header,須要注意的是,這個url請求的數據只是第一頁的數據,上拉加載的url接口形式是徹底不一樣的。json

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 解析器,咱們始終能夠經過細緻的觀察,找尋咱們須要的信息。咱們發現,下面這段代碼,隱藏着前十條文章的數據列表。微信

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 中,如今讓咱們來分析下數據:cookie

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 字段就是一組多圖文數據列表,在微信裏的展示形式是這樣的

如今咱們拿到了每篇文章的具體連接 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極客研修站

相關文章
相關標籤/搜索