Python爬蟲實現的微信公眾號文章下載器


平時愛逛知乎,收藏了不少別人推薦的數據分析、機器學習相關的微信公眾號(這里就不列舉了,以免硬廣嫌疑)。但是在手機微信上一頁頁的翻閱歷史文章瀏覽,很不方便,電腦端微信也不方便。

所以我就想有什么方法能否將這些公眾號文章下載下來。這樣的話,看起來也方便。但是網上的方法要么太復雜(對於我這個爬蟲入門新手來說),要么付費。

但我的需求其實卻很簡單——“方便的查找 / 檢索 / 瀏覽相關公眾號的任意文章”,所以,一番學習檢索后,上手做了一個小工具(打包成可執行文件了),雖然方法和代碼相當簡單,但實際上手用起來還是挺方便的。也給身邊伙伴安利了幾波。

工具需求:

輸入:給定公眾號ID,和用戶需要獲取的公眾號文章目錄頁碼數(小於已發布最大收錄頁數)
( 輸出Ⅰ:每個公眾號歷史文章信息csv文件(鏈接+標題)

輸出Ⅱ: wkhtmltopdf和pdfkit將html轉換成PDF文件或者圖片文件(初稿)

現有方案

之前在網上也搜索了些爬取微信公眾號的資料,大概有如下幾種

selenium爬取流程

  1. 安裝python selenium自動模塊,通過selenium中的webdriver驅動瀏覽器獲取Cookie登錄微信公眾號后台;

  2. 使用webdriver功能需要安裝對應瀏覽器的驅動插件
    注意:谷歌瀏覽器版本和chromedriver需要對應,否則會導致啟動時報錯。

  3. 微信公眾號登陸地址:https://mp.weixin.qq.com/

  4. 微信公眾號文章接口地址可以在微信公眾號后台中新建圖文消息,超鏈接功能中獲取:

  5. 搜索公眾號名稱

  6. 獲取要爬取的公眾號的fakeid

  7. 選定要爬取的公眾號,獲取文章接口地址

  8. 文章列表翻頁及內容獲取

AnyProxy代理批量采集

1、一個微信客戶端:可以是一台手機安裝了微信的app,或者是用電腦中的安卓模擬器。
2、一個微信個人號:為了采集內容不僅需要微信客戶端,還要有一個微信個人號專門用於采集。
3、本地代理服務器系統:通過Anyproxy代理服務器將公眾號歷史消息頁面中的文章列表發送到自己的服務器上。
4、文章列表分析與入庫系統,分析文章列表和建立采集隊列實現批量采集內容。


Fiddler設置代理和抓包

通過對多個賬號進行抓包分析,可以確定:

  • _biz:這個14位的字符串是每個公眾號的“id”,搜狗的微信平台可以獲得

  • uin:與訪問者有關,微信號id

  • key:和所訪問的公眾號有關

步驟:

1,寫按鍵精靈腳本,在手機上自動點擊公號文章列表頁,也就是“查看歷史消息”;
2,使用fiddler代理劫持手機端的訪問,將網址轉發到本地用php寫的網頁;
3,在php網頁上將接收到的網址備份到數據庫;
4,用python從數據庫取出網址,然后進行正常的爬取。

可能存在的問題:

如果只是想爬取文章內容,似乎並沒有訪問頻率限制,但如果想抓取閱讀數、點贊數,超過一定頻率后,返回就會變為空值。

付費平台

例如清博 新榜,如果只是想看數據的話,直接看每天的榜單就可以了,還不用花錢,如果需要接入自己的系統的話,他們也提供api接口

3項目步驟

3.1基本原理

目標爬取網站收錄了微信平台大部分的優質微信公眾號文章,會定期更新,經測試發現對爬蟲較為友好。
1、網站頁面布局排版規律,不同公眾號通過http://chuansong.me/account/almosthuman2014鏈接中的account區分
2、一個公眾號合集下的文章翻頁也有規律:id號每翻一頁+12

所以流程思路就是

  • 獲取預查詢微信公眾號ID(不是直接顯示的名稱,而是信息名片里的ID號,一般由數字字母組成)

  • 請求html頁面,判斷是否已經收錄改公眾號

  • 如果沒有收錄,則頁面顯示結果為:404該頁面不存在,所以直接使用正則表達式來匹配該提示信息即可

  • 正則匹配,找到目標公眾號最大收錄文章頁數

  • 解析請求頁面,提取文章鏈接和標題文字

  • 保存信息提取的結果

  • 調用pdfkit和wkhtmltopdf轉換網頁

3.2環境

  • win10(64bit)

  • Spyder(python3.6)

  • 安裝轉換工具包wkhtmltopdf

  • requests

  • pdfkit

    3.3公眾號信息檢索

    通過對目標url發起requset請求,獲取頁面html信息,然后調用正則方法匹配兩條信息
    1、該公眾號是否存在
    2、如果存在,最大的文章收錄頁數是多少  

    url = 'http://chuansong.me/account/' + str(name) + '?start=' + str(0)    
    wait = round(random.uniform(1,2),2) # 設置隨機爬蟲間隔,避免被封
    time.sleep(wait)    
    html = get_one_page(url)     
    pattern1 = re.compile('<h1>Page Not Found.</h1>', re.S)
    item1 = re.findall(pattern1, html)  # list類型    
    pattern2 = re.compile('<a href="/account/.*?">(.\d+)</a>(\s*)</span>(\s*?)<a href="/account/.*" style="float: right">下一頁</a>')
    item2 = re.findall(pattern2, html)  # list類型  
    if item1:
      print("\n---------該賬號信息尚未收錄--------\n") 
      exit();
    else:
      print("\n---------該公眾號目前已收錄文章頁數N為:",item2[0][0])

    當公眾號存在時,直接調用request解析目標請求鏈接。

    #需要加一個請求頭部,不然會被網站封禁
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'}
    try:       
      response = requests.get(url, headers=headers, timeout=10)
      response.raise_for_status #若不為200,則引發HTTPError錯誤
      response.encoding = response.apparent_encoding
      return response.text
    except:
      return "產生異常"

    注意,目標爬蟲網站必須要加headers,否則直接拒絕訪問

3.4正則解析,提取鏈接和文章標題

以下代碼用於從html文本中解析鏈接和標題文字信息

def parse_one_page(html):
    pattern = re.compile('<div class="feed_item_question">.*?<span>.*?<a class="question_link" href="(.*?)".*?_blank">(.*?)</a>.*?"timestamp".*?">(.*?)</span>', re.S)
    items = re.findall(pattern, html)      
    return items

3.5自動跳轉頁面

以下代碼通過循環遞增賦值,改變url中的頁碼參數

def main(offset, i):    
    url = 'http://chuansong.me/account/' + str(offset) + '?start=' + str(12*i)
    print(url)
    wait = round(random.uniform(1,2),2) # 設置隨機爬蟲間隔,避免被封
    time.sleep(wait)    
    html = get_one_page(url)    
    for item in parse_one_page(html):
        info = 'http://chuansong.me'+item[0]+','+ item[1]+','+item[2]+'\n'
        info = repr(info.replace('\n', ''))
        print(info)
        #info.strip('\"')  #這種去不掉首尾的“        
        #info = info[1:-1]  #這種去不掉首尾的“ 
        #info.Trim("".ToCharArray())
        #info.TrimStart('\"').TrimEnd('\"')
        write_to_file(info, offset)

3.6去掉標題中的非法字符

因為windows下文件命令,有些字符是不能用了,所以需要使用正則剔除

itle = re.sub('[\\\\/:*?\"<>|]', '', info.loc[indexs]['標題'])

3.7轉換html為PDF

使用pandas的read_csv函數讀取爬取的csv文件,循環遍歷“鏈接”,“標題”,“日期”
然后通過調用pdfkit函數轉換生成PDF文件

wait = round(random.uniform(1,2),2) # 設置隨機爬蟲間隔,避免被封
    time.sleep(wait) 
    path = get_path(offset) 
    path_wk = r'D:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe' #安裝wkhtmltopdf的位置
    config = pdfkit.configuration(wkhtmltopdf = path_wk)
    if path == "" :
        print("尚未抓取該公眾號")
    else:        
        info = get_url_info(offset)               
        for indexs in info.index:  
            url = info.loc[indexs]['鏈接']
            title = re.sub('[\\\\/:*?\"<>|]', '', info.loc[indexs]['標題'])
            date = info.loc[indexs]['日期']
            wait = round(random.uniform(4,5),2) # 設置隨機爬蟲間隔,避免被封
            time.sleep(wait)  
            print(url)
            with eventlet.Timeout(4,False):
                pdfkit.from_url(url, get_path(offset)+'\\'+ date+'_'+title+'.pdf', configuration=config)   
                print('轉換成功!')

3.8生成的PDF結果

4結果展示


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM