banner
andrewji8

Being towards death

Heed not to the tree-rustling and leaf-lashing rain, Why not stroll along, whistle and sing under its rein. Lighter and better suited than horses are straw sandals and a bamboo staff, Who's afraid? A palm-leaf plaited cape provides enough to misty weather in life sustain. A thorny spring breeze sobers up the spirit, I feel a slight chill, The setting sun over the mountain offers greetings still. Looking back over the bleak passage survived, The return in time Shall not be affected by windswept rain or shine.
telegram
twitter
github

驚!Python爬蟲只需10行代碼,海量公眾號文章任你爬!

前言
自從 chatGPT 出現後,對於文本處理的能力直接上升了一個維度。在這之前,我們爬取到網路上的文本內容之後,都需要寫一個文本清理的程序,對文本進行清洗,而現在,有了 chatGPT 的加持,我們只需要幾秒,就可以很方便對所有類型,所有格式的文本內容,完成清洗,去除那些 html 標籤等。
對於清洗後的文章,我們仍然可以做很多事情,比如,提取核心觀點,文章改寫等操作,使用 chatGPT 都可以很輕鬆的解決。

早在 2019 年,我就寫過一篇文章,介紹爬蟲爬取公眾號文章的方法,現在看來依然適用,只不過,當時我們對於爬到的文章,後續基本沒有什麼處理了,但是現在不同了,我們可以做很多事情,不過前提是不要違反法律法規。

獲取文章的 URL
爬蟲爬取網路資源,最重要的就是可以找到目標網站的 url 地址,然後尋找規律,遍歷地址逐個或多線程進行爬取。一般獲取地址的方式,一是通過網頁分頁,推斷出 url 地址的規律嗎,比如通過參數 pageNum = num 等,只需要將 num 進行累加即可。另外一種是隱藏在 HTML 中的,我們需要解析出當前網頁的超鏈接,如 <a href="url">,取出 url 作為後續爬取的地址。

遺憾的是,微信公眾號對於這兩種方式都很難使用,我們可以在網頁中打開一個微信公眾號地址,可以看下它的 url 格式,

https://mp.weixin.qq.com/s?__biz=MzIxMTgyODczNg==&mid=2247483660&idx=1&sn=2c14b9b416e2d8eeed0cbbc6f44444e9&chksm=974e2863a039a1752605e6e76610eb39e5855c473edab16ab2c7c8aa2f624b4d892d26130110&token=20884314&lang=zh_CN#rd
除了前面的域名,後面的參數完全就是沒有規律可循,而且,在一篇文章中,也沒有辦法鏈接到下一篇文章,我們無法從一篇文章開始,爬取到這個公眾號下的所有文章。

但好在,我們依然有辦法批量獲取到某個公眾號下的所有文章地址,我們只需要將其保存下來,後續再遍歷爬取就變得輕鬆很多。

1. 首先,你要有一個公眾號,如果沒有的話,可以註冊一個,這個是前提條件。註冊公眾號的步驟比較簡單,可以自行操作。
2. 註冊好之後,登錄微信公眾平台,點擊左側草稿箱,新建圖文

640 (1)
3. 進入新建圖文頁面,點擊頂端的超鏈接,出現一個彈窗,選擇公眾號文章,輸入你要爬取的公眾號的名稱,如下所示:

640 (2)
4. 選中之後,你就可以看到這個公眾號下的所有文章的列表了,這個時候,打開 F12,查看網頁裡面的網路請求。

640 (3)
當你點擊下一頁的時候,可以看到請求的 url,還有攜帶的業務參數以及請求頭參數。

640 (4)
上面就是一些業務參數,這些參數很容易理解,比較重要的是 begin 指的是從第幾個開始查詢,count 指的是一次列表查詢多少個,fakeid 是公眾號的唯一標識,每個公眾號不一樣,如果爬取其他公眾號的,只需要更改這個參數就可以了。其中 random 可以省略。還可以看到相應結果:

640 (5)
編寫代碼
有了上述這些信息,我們就可以編寫代碼了,我使用的是 python3.8,首先,定義 url,header 和所需要的參數

# 目標url
url = "https://mp.weixin.qq.com/cgi-bin/appmsg"
# 請求頭參數
headers = {
  "Cookie": "ua_id=YF6RyP41YQa2QyQHAAAAAGXPy_he8M8KkNCUbRx0cVU=; pgv_pvi=2045358080; pgv_si=s4132856832; uuid=48da56b488e5c697909a13dfac91a819; bizuin=3231163757; ticket=5bd41c51e53cfce785e5c188f94240aac8fad8e3; ticket_id=gh_d5e73af61440; cert=bVSKoAHHVIldcRZp10_fd7p2aTEXrTi6; noticeLoginFlag=1; remember_acct=mf1832192%40smail.nju.edu.cn; data_bizuin=3231163757; data_ticket=XKgzAcTceBFDNN6cFXa4TZAVMlMlxhorD7A0r3vzCDkS++pgSpr55NFkQIN3N+/v; slave_sid=bU0yeTNOS2VxcEg5RktUQlZhd2xheVc5bjhoQTVhOHdhMnN2SlVIZGRtU3hvVXJpTWdWakVqcHowd3RuVF9HY19Udm1PbVpQMGVfcnhHVGJQQTVzckpQY042QlZZbnJzel9oam5SdjRFR0tGc0c1eExKQU9ybjgxVnZVZVBtSmVnc29ZcUJWVmNWWEFEaGtk; slave_user=gh_d5e73af61440; xid=93074c5a87a2e98ddb9e527aa204d0c7; openid2ticket_obaWXwJGb9VV9FiHPMcNq7OZzlzY=lw6SBHGUDQf1lFHqOeShfg39SU7awJMxhDVb4AbVXJM=; mm_lang=zh_CN",
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36",
}

# 業務參數
data = {
    "token": "1378111188",
    "lang": "zh_CN",
    "f": "json",
    "ajax": "1",
    "action": "list_ex",
    "begin": "0",
    "count": "5",
    "query": "",
    "fakeid": "MzU5MDUzMTk5Nw==",
    "type": "9",
}

cookie 和 token 需要根據自己請求 URL 中的進行更改,然後發送請求獲取響應,並對響應結果進行解析。

content_list = []
for i in range(20):
    data["begin"] = i*5
    time.sleep(5)
    # 使用get方法進行提交
    content_json = requests.get(url, headers=headers, params=data).json()
    # 返回了一個json,裡面是每一頁的數據
    for item in content_json["app_msg_list"]:    
    # 提取每頁文章的標題及對應的url
        items = []
        items.append(item["title"])
        items.append(item["link"])
        t = time.localtime(item["create_time"])
        items.append(time.strftime("%Y-%m-%d %H:%M:%S", t))
        content_list.append(items)

第一個 for 循環是爬取的頁數,這裡建議一次爬取 20 頁,每一頁 5 條數據,就是 100 篇文章了,首先需要看好公眾號的歷史文章列表一共有多少頁,這個數只能小於頁數。更改 data [“begin”],表示從第幾條開始,每次 5 條,注意爬取不能夠太多和太頻繁,所以需要每次爬取等待幾秒鐘,不然會被封 ip 封 cookie,嚴重還會封公眾號。

最後,我們只需要把標題和 url 保存起來就可以了,保存起來後,就可以逐個爬取了。

name = ['title', 'link', 'create_time']
test = pd.DataFrame(columns=name, data=content_list)
test.to_csv("url.csv", mode='a', encoding='utf-8')

為了獲取所有的歷史文章,需要得到文章總數,從 app_msg_cnt 中獲取,然後計算一共有多少頁,就可以一次性爬取所有文章了。

content_json = requests.get(url, headers=headers, params=data).json()
count = int(content_json["app_msg_cnt"])
print(count)
page = int(math.ceil(count / 5))
print(page)

為了抓取的不夠頻繁,我們需要不斷 sleep 一段時間,我們可以爬取 10 次之後,就讓程序 sleep 幾秒

if (i > 0) and (i % 10 == 0):
        name = ['title', 'link', 'create_time']
        test = pd.DataFrame(columns=name, data=content_list)
        test.to_csv("url.csv", mode='a', encoding='utf-8')
        print("第" + str(i) + "次保存成功")
        content_list = []
        time.sleep(random.randint(60,90))
    else:
        time.sleep(random.randint(15,25))

640 (6)
完整的代碼,放在 GitHub 上了,可以直接下載使用
https://github.com/cxyxl66/WeChatCrawler

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。