微信公衆號採集小爬蟲

   最近在做一個自己的項目,涉及到需要通過python爬取微信公衆號的文章,因爲微信獨特一些手段,導致無法直接爬取,研究了一些文章大概有了思路,並且網上目前能搜到的方案思路都沒啥問題,但是裏面的代碼因爲一些三方庫的變動基本都不能用了,這篇文章寫給需要爬取公衆號文章的朋友們,文章最後也會提供python源碼下載。

## 公衆號爬取方式

爬取公衆號目前主流的方案主要有兩種,一種是通過搜狗搜索微信公衆號的頁面去找到文章地址,再去爬取具體文章內容;第二種是通過註冊公衆號然後通過公衆號的搜索接口去查詢到文章地址,然後再根據地址去爬文章內容。

這兩種方案各有優缺點,通過搜狗搜索來做其實核心思路就是通過request模擬搜狗搜索公衆號,然後解析搜索結果頁面,再根據公衆號主頁地址爬蟲,爬取文章明細信息,但是這裏需要注意下,因爲搜狗和騰訊之間的協議問題,只能顯示最新的10條文章,沒辦法拿到所有的文章。如果要拿到所有文章的朋友可能要採用第二種方式了。第二種方式的缺點就是要註冊公衆號通過騰訊認證,流程麻煩些,通過調用接口公衆號查詢接口查詢,但是翻頁需要通過selenium去模擬滑動翻頁操作,整個過程還是挺麻煩的。因爲我的項目裏不需要歷史文章,所以我採用通過搜狗搜索去做爬取公衆號的功能。



爬取最近10篇公衆號文章

python需要依賴的三方庫如下:

urllib、pyquery、requests、selenium

具體的邏輯都寫在註釋裏了,沒有特別複雜的地方。

爬蟲核心類

```python
#!/usr/bin/python
# coding: utf-8

import sys
 
reload(sys)
sys.setdefaultencoding('utf-8')
 
from urllib import quote
from pyquery import PyQuery as pq
 
import requests
import time
import re
import os
 
from selenium.webdriver import Chrome
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.wait import WebDriverWait
 
 
# 搜索入口地址,以公衆爲關鍵字搜索該公衆號
def get_search_result_by_keywords(sogou_search_url):
    # 爬蟲僞裝頭部設置
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0'}
 
    # 設置操作超時時長
    timeout = 5
    # 爬蟲模擬在一個request.session中完成
    s = requests.Session()
    log(u'搜索地址爲:%s' % sogou_search_url)
    return s.get(sogou_search_url, headers=headers, timeout=timeout).content
 
 
# 獲得公衆號主頁地址
def get_wx_url_by_sougou_search_html(sougou_search_html):
    doc = pq(sougou_search_html)
    return doc('div[class=txt-box]')('p[class=tit]')('a').attr('href')
 
 
# 使用webdriver 加載公衆號主頁內容,主要是js渲染的部分
def get_selenium_js_html(url):
    options = Options()
    options.add_argument('-headless')  # 無頭參數
    driver = Chrome(executable_path='chromedriver', chrome_options=options)
    wait = WebDriverWait(driver, timeout=10)
 
    driver.get(url)
    time.sleep(3)
    # 執行js得到整個頁面內容
    html = driver.execute_script("return document.documentElement.outerHTML")
    driver.close()
    return html
 
 
# 獲取公衆號文章內容
def parse_wx_articles_by_html(selenium_html):
    doc = pq(selenium_html)
    return doc('div[class="weui_media_box appmsg"]')
 
 
# 將獲取到的文章轉換爲字典
def switch_arctiles_to_list(articles):
    # 定義存貯變量
    articles_list = []
    i = 1
 
    # 遍歷找到的文章,解析裏面的內容
    if articles:
        for article in articles.items():
            log(u'開始整合(%d/%d)' % (i, len(articles)))
            # 處理單個文章
            articles_list.append(parse_one_article(article))
            i += 1
    return articles_list
 
 
# 解析單篇文章
def parse_one_article(article):
    article_dict = {}
 
    # 獲取標題
    title = article('h4[class="weui_media_title"]').text().strip()
    ###log(u'標題是: %s' % title)
    # 獲取標題對應的地址
    url = 'http://mp.weixin.qq.com' + article('h4[class="weui_media_title"]').attr('hrefs')
    log(u'地址爲: %s' % url)
    # 獲取概要內容
    summary = article('.weui_media_desc').text()
    log(u'文章簡述: %s' % summary)
    # 獲取文章發表時間
    date = article('.weui_media_extra_info').text().strip()
    log(u'發表時間爲: %s' % date)
    # 獲取封面圖片
    pic = parse_cover_pic(article)
 
    # 返回字典數據
    return {
        'title': title,
        'url': url,
        'summary': summary,
        'date': date,
        'pic': pic
    }
 
 
# 查找封面圖片,獲取封面圖片地址
def parse_cover_pic(article):
    pic = article('.weui_media_hd').attr('style')
 
    p = re.compile(r'background-image:url\((.*?)\)')
    rs = p.findall(pic)
    log(u'封面圖片是:%s ' % rs[0] if len(rs) > 0 else '')
 
    return rs[0] if len(rs) > 0 else ''
 
 
# 自定義log函數,主要是加上時間
def log(msg):
    print u'%s: %s' % (time.strftime('%Y-%m-%d_%H-%M-%S'), msg)
 
 
# 驗證函數
def need_verify(selenium_html):
    ' 有時候對方會封鎖ip,這裏做一下判斷,檢測html中是否包含id=verify_change的標籤,有的話,代表被重定向了,提醒過一陣子重試 '
    return pq(selenium_html)('#verify_change').text() != ''
 
 
# 創建公衆號命名的文件夾
def create_dir(keywords):
    if not os.path.exists(keywords):
        os.makedirs(keywords)
 
        # 爬蟲主函數
 
 
def run(keywords):
    ' 爬蟲入口函數 '
    # Step 0 :  創建公衆號命名的文件夾
    create_dir(keywords)
 
    # 搜狐微信搜索鏈接入口
    sogou_search_url = 'http://weixin.sogou.com/weixin?type=1&query=%s&ie=utf8&s_from=input&_sug_=n&_sug_type_=' % quote(
        keywords)
 
    # Step 1:GET請求到搜狗微信引擎,以微信公衆號英文名稱作爲查詢關鍵字
    log(u'開始獲取,微信公衆號英文名爲:%s' % keywords)
    log(u'開始調用sougou搜索引擎')
    sougou_search_html = get_search_result_by_keywords(sogou_search_url)
 
    # Step 2:從搜索結果頁中解析出公衆號主頁鏈接
    log(u'獲取sougou_search_html成功,開始抓取公衆號對應的主頁wx_url')
    wx_url = get_wx_url_by_sougou_search_html(sougou_search_html)
    log(u'獲取wx_url成功,%s' % wx_url)
 
    # Step 3:Selenium+PhantomJs獲取js異步加載渲染後的html
    log(u'開始調用selenium渲染html')
    selenium_html = get_selenium_js_html(wx_url)
 
    # Step 4: 檢測目標網站是否進行了封鎖
    if need_verify(selenium_html):
        log(u'爬蟲被目標網站封鎖,請稍後再試')
    else:
        # Step 5: 使用PyQuery,從Step 3獲取的html中解析出公衆號文章列表的數據
        log(u'調用selenium渲染html完成,開始解析公衆號文章')
        articles = parse_wx_articles_by_html(selenium_html)
        log(u'抓取到微信文章%d篇' % len(articles))
 
        # Step 6: 把微信文章數據封裝成字典的list
        log(u'開始整合微信文章數據爲字典')
        articles_list = switch_arctiles_to_list(articles)
        return [content['title'] for content in articles_list]
 
```
 
main入口函數:
 
```python
# coding: utf8
import spider_weixun_by_sogou
 
if __name__ == '__main__':
 
    gongzhonghao = raw_input(u'input weixin gongzhonghao:')
    if not gongzhonghao:
        gongzhonghao = 'spider'
    text = " ".join(spider_weixun_by_sogou.run(gongzhonghao))
 
    print text

 爬取公衆號注意事項
下面這3個是我在爬取的過程中遇到的一些問題,希望能幫到大家避坑。

1. Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead   warnings.warn('Selenium support for PhantomJS has been deprecated, please use headless ' 

   網上很多的文章都還在使用PhantomJS,其實從去年Selenium就已經不支持PhantomJS了,現在使用Selenium初始化瀏覽器的話需要使用webdriver初始化無頭參數的Chrome或者Firefox driver。

   具體可以參考官網鏈接:https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode

2. Can not connect to the Service chromedriver/firefoxdriver

   在開發過程中還遇到這個坑,這個問題一般有兩種可能性,一種是沒有配置chromedriver或者geckodriver的環境變量,這裏需要注意下將chromedriver或者geckodriver文件一定要配置環境變量到PATH下,或者乾脆粗暴一點直接將這兩個文件複製到/usr/bin目錄下;

   還有種可能是沒有配置hosts,如果大家發現這個問題檢查下自己的hosts文件是不是沒有配置`127.0.0.1 localhost`,只要配置上就好了。

   這裏還有一點要注意的就是使用chrome瀏覽器的話,還要注意chrome瀏覽器版本和chromedriver的對應關係,可以在這篇文章中查看也可以翻牆去google官網查看最新的對應關係。https://www.cnblogs.com/JHblogs/p/7699951.html

3. 防盜鏈

   微信公衆號對文章中的圖片做了防盜鏈處理,所以如果在公衆號和小程序、PC瀏覽器以外的地方是無法顯示圖片的,這裏推薦大家可以看下這篇文章瞭解下如何處理微信的防盜鏈。

    https://blog.csdn.net/tjcyjd/article/details/74643521

總結

好了上面說了那麼多,大家最關心的就是源代碼,這裏放出github地址: https://github.com/feiweiwei/WeixinSpider.git,好用的話記得strar。

 另外附上作品項目:http://zhimo.yuanzhumuban.cc/blog/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章