搞定,爬取公眾號(hào)文章轉(zhuǎn)換成PDF,自動(dòng)郵件發(fā)送給自己!
↑↑↑關(guān)注后"星標(biāo)"簡(jiǎn)說Python
人人都可以簡(jiǎn)單入門Python、爬蟲、數(shù)據(jù)分析 簡(jiǎn)說Python發(fā)布 來源:簡(jiǎn)說Python 作者:老表
大家好,我是老表!
今天給大家分享如何每天定時(shí)爬取公眾號(hào)文章鏈接和標(biāo)題,并將內(nèi)容轉(zhuǎn)換成PDF,以附件的形式通過郵件發(fā)送給自己的小技巧(腳本)。
一、寫在前面
這也是一個(gè)讀者的需求,之前也有讀者提到過,趁五一還在假期中(調(diào)休幾天),給大家一并解決了,拿到需求,先簡(jiǎn)單分析下,然后百度下,基本解決方法就有了,哈哈哈哈!
最后呈現(xiàn)效果:

本需求主要分為三個(gè)部分:
爬取到公眾號(hào)發(fā)布文章的鏈接和標(biāo)題
這塊,目前網(wǎng)絡(luò)上有的一些方法有:從搜狗微信上爬?。ㄓ袀€(gè)現(xiàn)成的框架wechatsogou[1],不過好像已經(jīng)好久沒人維護(hù)了,鏈接獲取功能測(cè)試失?。?、從微信公眾號(hào)后臺(tái)爬取(需要大家注冊(cè)微信公眾號(hào),麻煩),這里我用的方法是直接從第三方數(shù)據(jù)平臺(tái)爬?。ê?jiǎn)單)。
我選擇了志軍大佬開發(fā)的二十次冪平臺(tái)[2],這里也給大家安利下這個(gè)網(wǎng)站,除了一些公眾號(hào)主可以用,讀者朋友也可以在上面查看全網(wǎng)熱文以及喜歡的公眾號(hào)的歷史文章等。
將公眾號(hào)鏈接內(nèi)容轉(zhuǎn)換為pdf
這里利用pdfkit這個(gè)庫(kù),避免直接通過url轉(zhuǎn)換成pdf時(shí)出現(xiàn)的無法顯示圖片問題,我們本次引用了wechatsogou[1]中的get_article_content函數(shù),將url中的代碼提取出來轉(zhuǎn)換為html字符串,具體源碼我簡(jiǎn)單看了下,有興趣的也可以私聊我一起研究下(空閑的時(shí)候)。
通過郵件將pdf以附件形式發(fā)送
這一步蠻簡(jiǎn)單的,利用yagmail模塊實(shí)現(xiàn)郵件發(fā)送功能,在開始前,我們需要先在對(duì)應(yīng)郵箱的設(shè)置中打開POP3/SMTP服務(wù),這樣才能使用,不然會(huì)提示沒有權(quán)限。

二、基本知識(shí)概要
爬蟲,利用requests發(fā)送get請(qǐng)求 requests.get(url,headers=headers) json將json格式字符串轉(zhuǎn)為Python字典格式 json.loads(json_string) 基本反爬和反反爬策略 pdfkit將文本內(nèi)容或者url鏈接內(nèi)容轉(zhuǎn)換成pdf wechatsogou搜狗微信爬蟲框架 正則表達(dá)式re.sub函數(shù)和字符串處理函數(shù)replace yagmail.SMTP自動(dòng)發(fā)送郵件 markdown語法寫郵件內(nèi)容(格式) 字符串傳多個(gè)參數(shù)format函數(shù) os模塊基本操作,獲取當(dāng)前文件目錄、創(chuàng)建文件夾等 datetime模塊獲取當(dāng)前日期并前推一天 sys模塊exit()結(jié)束當(dāng)前程序
等。。。
三、開始動(dòng)手動(dòng)腦
3.1 本次項(xiàng)目需要導(dǎo)入的庫(kù)
import requests # 發(fā)送get/post請(qǐng)求,獲取網(wǎng)站內(nèi)容
import wechatsogou # 微信公眾號(hào)文章爬蟲框架
import json # json數(shù)據(jù)處理模塊
import datetime # 日期數(shù)據(jù)處理模塊
import pdfkit # 可以將文本字符串/鏈接/文本文件轉(zhuǎn)換成為pdf
import os # 系統(tǒng)文件管理
import re # 正則匹配模塊
import yagmail # 郵件發(fā)送模塊
import sys # 項(xiàng)目進(jìn)程管理
3.2 爬取到公眾號(hào)發(fā)布文章的鏈接和標(biāo)題
'''
1、從二十次冪獲取公眾號(hào)最新的推文鏈接和標(biāo)題
'''
def get_data(publish_date):
# 添加Cookie 記錄登錄狀態(tài)
header = {
'Cookie': "獲取方法見下文"
}
# 可以自定義設(shè)置獲取文章的發(fā)布時(shí)間區(qū)間,日期越多,獲取到的文章越多,本項(xiàng)目默認(rèn)獲取前一天的數(shù)據(jù)
start_at = publish_date
end_at = publish_date # 每次只爬去前一天的數(shù)據(jù)
url1 = 'https://www.ershicimi.com/api/stats/articles?'
# bid=EOdxnBO4 表示公眾號(hào) 簡(jiǎn)說Python,每個(gè)公眾號(hào)都有對(duì)應(yīng)的bid,可以直接搜索查看
url2 = 'page=1&page_size=50&bid=EOdxnBO4&start_at={0}&end_at={1}&position=all'.format(start_at,end_at)
url3 = url1+url2
r = requests.get(url3, headers=header)
json_data = json.loads(r.text)
html_data = json_data['data']['articles']
# print(html_data)
return html_data
如何獲取你自己登錄二十次冪后的Cookie:首先我們需要知道為什么需要這個(gè)玩意。我們?nèi)绻苯釉L問我上面提供的鏈接會(huì)發(fā)現(xiàn)print(html_data)出來的是登錄頁(yè)面的源碼,這也是一個(gè)比較基本的反爬手段--需要登錄后才可以訪問網(wǎng)站內(nèi)的數(shù)據(jù)。
針對(duì)這個(gè)反爬手段,最簡(jiǎn)單的反反爬蟲手段就是手動(dòng)登錄后獲取Cookie,這里會(huì)記錄我們的登錄信息,讓我們?cè)僭L問這類頁(yè)面的時(shí)候讓系統(tǒng)以為我們是已經(jīng)登錄過了的人,不過Cookie是有時(shí)效的,所以這種方法還蠻麻煩的。
還有種簡(jiǎn)單方法,直接通過代碼傳參,然后登錄二十次冪,保持Session,然后再去訪問我們想訪問的數(shù)據(jù)頁(yè)面就可以了,這個(gè)我簡(jiǎn)單的利用requests.session()試了下,沒成功,有興趣的同學(xué)可以試試,這樣就不用每天運(yùn)行代碼前還需要手動(dòng)到頁(yè)面登錄獲取Cookie,歡迎試成功的同學(xué)在評(píng)論區(qū)或者微信和我分享下,我也會(huì)第一時(shí)間和大家分享。
手動(dòng)獲取Cookie方法:1)注冊(cè)好二十次冪后(網(wǎng)站地址見文末參考鏈接注釋),在登錄頁(yè)面填寫賬號(hào)相關(guān)信息,點(diǎn)擊登錄按鈕登錄。
2)按住F12調(diào)出瀏覽器的開發(fā)者工具,選擇Network,然后刷新頁(yè)面,在Network會(huì)出現(xiàn)網(wǎng)頁(yè)加載過程中的一些內(nèi)容,找到下圖中打紅框的login?next=%2Fsearch%2Faccount,點(diǎn)擊一下,右側(cè)就會(huì)出現(xiàn)請(qǐng)求相關(guān)信息,找到Request Headers中的Cookie后對(duì)應(yīng)的一長(zhǎng)串字符串就是我們需要的Cookie值。
3.3 將公眾號(hào)鏈接內(nèi)容轉(zhuǎn)換為pdf
'''
2、for循環(huán)遍歷,將每篇文章轉(zhuǎn)化為pdf
'''
# 轉(zhuǎn)化url為pdf時(shí),調(diào)用wechatsogou中的get_article_content函數(shù),將url中的代碼提取出來轉(zhuǎn)換為html字符串
# 這里先初始化一個(gè)WechatSogouAPI對(duì)象
ws_api = wechatsogou.WechatSogouAPI(captcha_break_time=3)
def url_to_pdf(url, title, targetPath, publish_date):
'''
使用pdfkit生成pdf文件
:param url: 文章url
:param title: 文章標(biāo)題
:param targetPath: 存儲(chǔ)pdf文件的路徑
:param publish_date: 文章發(fā)布日期,作為pdf文件名開頭(標(biāo)識(shí))
'''
try:
content_info = ws_api.get_article_content(url)
except:
return False
# 處理后的html
html = f'''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{title}</title>
</head>
<body>
<h2 style="text-align: center;font-weight: 400;">{title}</h2>
{content_info['content_html']}
</body>
</html>
'''
# html字符串轉(zhuǎn)換為pdf
filename = publish_date + '-' + title
# 部分文章標(biāo)題含特殊字符,不能作為文件名
# 去除標(biāo)題中的特殊字符 win / \ : * " < > | ?mac :
# 先用正則去除基本的特殊字符,python中反斜線很煩,最后用replace函數(shù)去除
filename = re.sub('[/:*"<>|?]','',filename).replace('\\','')
pdfkit.from_string(html, targetPath + os.path.sep + filename + '.pdf')
return filename # 返回存儲(chǔ)路徑,后面郵件發(fā)送附件需要
這里為了解決pdfkit直接轉(zhuǎn)換url成為pdf會(huì)出現(xiàn)圖片無法顯示問題,參考了博客園xuzifan[3]提供的思路,利用wechatsogou中的get_article_content函數(shù),將url中的代碼提取出來轉(zhuǎn)換為html字符串,然后將html字符串轉(zhuǎn)換為pdf,完美解決。
這里需要注意的是:使用pdfkit需要提前訪問wkhtmltopdf下載地址[4]下載并安裝好wkhtmltopdf。如果是mac蠻簡(jiǎn)單的,直接下載安裝即可,如果是windows需要下載安裝后將安裝路徑添加到系統(tǒng)環(huán)境變量中或者修改轉(zhuǎn)換pdf代碼(如下)。
config=pdfkit.configuration(wkhtmltopdf='你的wkhtmltopdf安裝路徑'))
pdfkit.from_string(html, targetPath + os.path.sep + filename + '.pdf', configuration=config)
3.4 通過郵件將pdf以附件形式發(fā)送
'''
3、通過郵件將新生成的文件發(fā)送到自己的郵箱
'''
def send_email(user_name, email, gzh_data):
yag = yagmail.SMTP(user='你的郵箱',password='你的POP3/SMTP服務(wù)密鑰',host='smtp.163.com')
contents = ['親愛的 '+user_name+' 你好:<br>',
'公眾號(hào) {0} {1}發(fā)布了{(lán)2}篇推文,推文標(biāo)題分別為:<br>'.format(gzh_data['gzh_name'], gzh_data['publish_date'], len(gzh_data['save_path'])),
'<br>'.join(gzh_data['save_path']),
'<br>文章詳細(xì)信息可以查看附件pdf內(nèi)容,有問題可以在公眾號(hào)%s聯(lián)系作者提問。<br>'%gzh_data['gzh_name'],
'<br><br><p align="right">公眾號(hào)-%s</p>'%gzh_data['gzh_name']
]
# 在郵件內(nèi)容后,添加上附件路徑(蠻簡(jiǎn)單實(shí)現(xiàn)動(dòng)態(tài)添加附件,直接拼接兩個(gè)列表即可哈哈哈哈)
contents = contents + [targetPath + os.path.sep + i + '.pdf' for i in gzh_data['save_path']]
yag.send(email, '請(qǐng)查看'+gzh_name+publish_date+'推文內(nèi)容', contents)
yagmail可以實(shí)現(xiàn)簡(jiǎn)單的自動(dòng)發(fā)送郵件功能,我也拿來做過批量發(fā)送,蠻好用的,還支持markdown語法對(duì)郵件內(nèi)容進(jìn)行排版,蠻好的。
yag = yagmail.SMTP(user='你的郵箱',password='你的POP3/SMTP服務(wù)密鑰',host='smtp.163.com')
這里需要注意的是,代碼里的user就是你的郵箱地址,比如[email protected],password不是你的郵箱密碼,而是你在郵箱頁(yè)面開啟POP3/SMTP服務(wù)后,系統(tǒng)給到的一個(gè)碼,下面以163郵箱為例子給大家介紹如何獲取這個(gè)password。
1)在網(wǎng)站登錄對(duì)應(yīng)的郵箱;
2)點(diǎn)擊設(shè)置按鈕,然后選擇POP3/SMTP/IMAP,進(jìn)入到相關(guān)設(shè)置頁(yè)面。
3)點(diǎn)擊POP3/SMTP服務(wù)后的 開啟 按鈕,然后驗(yàn)證下即可,完成后會(huì)有彈框提示,授權(quán)密碼就是我們要的password。


3.5 定時(shí)每天自動(dòng)執(zhí)行程序
今天回杭州,路上寫了一天,顛顛倒倒,這個(gè)功能就開放留給大家啦,大家寫出后可以留言區(qū)將自己的方案寫上,第一個(gè)給出方案的讀者朋友可以獲得Python自動(dòng)化測(cè)試相關(guān)圖書一本。
全部代碼:
import requests # 發(fā)送get/post請(qǐng)求,獲取網(wǎng)站內(nèi)容
import wechatsogou # 微信公眾號(hào)文章爬蟲框架
import json # json數(shù)據(jù)處理模塊
import datetime # 日期數(shù)據(jù)處理模塊
import pdfkit # 可以將文本字符串/鏈接/文本文件轉(zhuǎn)換成為pdf
import os # 系統(tǒng)文件管理
import re # 正則匹配模塊
import yagmail # 郵件發(fā)送模塊
import sys # 項(xiàng)目進(jìn)程管理
'''
1、從二十次冪獲取公眾號(hào)最新的推文鏈接和標(biāo)題
'''
def get_data(publish_date):
# 添加Cookie 記錄登錄狀態(tài)
header = {
'Cookie': "獲取方法見上文介紹"
}
# 可以自定義設(shè)置獲取文章的發(fā)布時(shí)間區(qū)間,日期越多,獲取到的文章越多,本項(xiàng)目默認(rèn)獲取前一天的數(shù)據(jù)
start_at = publish_date
end_at = publish_date # 每次只爬去前一天的數(shù)據(jù)
url1 = 'https://www.ershicimi.com/api/stats/articles?'
# bid=EOdxnBO4 表示公眾號(hào) 簡(jiǎn)說Python,每個(gè)公眾號(hào)都有對(duì)應(yīng)的bid,可以直接搜索查看
url2 = 'page=1&page_size=50&bid=EOdxnBO4&start_at={0}&end_at={1}&position=all'.format(start_at,end_at)
url3 = url1+url2
r = requests.get(url3, headers=header)
json_data = json.loads(r.text)
html_data = json_data['data']['articles']
# print(html_data)
return html_data
'''
2、for循環(huán)遍歷,將每篇文章轉(zhuǎn)化為pdf
'''
# 轉(zhuǎn)化url為pdf時(shí),調(diào)用wechatsogou中的get_article_content函數(shù),將url中的代碼提取出來轉(zhuǎn)換為html字符串
# 這里先初始化一個(gè)WechatSogouAPI對(duì)象
ws_api = wechatsogou.WechatSogouAPI(captcha_break_time=3)
def url_to_pdf(url, title, targetPath, publish_date):
'''
使用pdfkit生成pdf文件
:param url: 文章url
:param title: 文章標(biāo)題
:param targetPath: 存儲(chǔ)pdf文件的路徑
:param publish_date: 文章發(fā)布日期,作為pdf文件名開頭(標(biāo)識(shí))
'''
try:
content_info = ws_api.get_article_content(url)
except:
return False
# 處理后的html
html = f'''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{title}</title>
</head>
<body>
<h2 style="text-align: center;font-weight: 400;">{title}</h2>
{content_info['content_html']}
</body>
</html>
'''
# html字符串轉(zhuǎn)換為pdf
filename = publish_date + '-' + title
# 部分文章標(biāo)題含特殊字符,不能作為文件名
# 去除標(biāo)題中的特殊字符 win / \ : * " < > | ?mac :
# 先用正則去除基本的特殊字符,python中反斜線很煩,最后用replace函數(shù)去除
filename = re.sub('[/:*"<>|?]','',filename).replace('\\','')
pdfkit.from_string(html, targetPath + os.path.sep + filename + '.pdf')
return filename # 返回存儲(chǔ)路徑,后面郵件發(fā)送附件需要
'''
3、通過郵件將新生成的文件發(fā)送到自己的郵箱
'''
def send_email(user_name, email, gzh_data):
yag = yagmail.SMTP(user='你的發(fā)郵件的郵箱,可以和收件的是一個(gè)',password='你的POP3/SMTP服務(wù)密鑰',host='smtp.163.com')
contents = ['親愛的 '+user_name+' 你好:<br>',
'公眾號(hào) {0} {1}發(fā)布了{(lán)2}篇推文,推文標(biāo)題分別為:<br>'.format(gzh_data['gzh_name'], gzh_data['publish_date'], len(gzh_data['save_path'])),
'<br>'.join(gzh_data['save_path']),
'<br>文章詳細(xì)信息可以查看附件pdf內(nèi)容,有問題可以在公眾號(hào)%s聯(lián)系作者提問。<br>'%gzh_data['gzh_name'],
'<br><br><p align="right">公眾號(hào)-%s</p>'%gzh_data['gzh_name']
]
# 在郵件內(nèi)容后,添加上附件路徑(蠻簡(jiǎn)單實(shí)現(xiàn)動(dòng)態(tài)添加附件,直接拼接兩個(gè)列表即可哈哈哈哈)
contents = contents + [targetPath + os.path.sep + i + '.pdf' for i in gzh_data['save_path']]
yag.send(email, '請(qǐng)查看'+gzh_name+publish_date+'推文內(nèi)容', contents)
# 程序開始
# 0、為爬取內(nèi)容創(chuàng)建一個(gè)單獨(dú)的存放目錄
gzh_name = '簡(jiǎn)說Python' # 爬取公眾號(hào)名稱
targetPath = os.getcwd() + os.path.sep + gzh_name
# 如果不存在目標(biāo)文件夾就進(jìn)行創(chuàng)建
if not os.path.exists(targetPath):
os.makedirs(targetPath)
print('------pdf存儲(chǔ)目錄創(chuàng)建成功!')
# 1、從二十次冪獲取微信公眾號(hào)最新文章數(shù)據(jù)
year = str(datetime.datetime.now().year)
month = str(datetime.datetime.now().month)
day = str(datetime.datetime.now().day-1)
publish_date = datetime.datetime.strptime(year+month+day,'%Y%m%d').strftime('%Y-%m-%d') # 文章發(fā)布日期
html_data = get_data(publish_date)
if html_data:
print('------成功獲取到公眾號(hào){0}{1}推文鏈接!'.format(gzh_name, publish_date))
else:
print('------公眾號(hào){0}{1}沒有發(fā)布推文,請(qǐng)前往微信確認(rèn)'.format(gzh_name, publish_date))
sys.exit() # 結(jié)束進(jìn)程
# 2、for循環(huán)遍歷,將每篇文章轉(zhuǎn)化為pdf
save_path = []
for article in html_data:
url = article['content_url']
title = article['title']
# 將文章鏈接內(nèi)容轉(zhuǎn)化為pdf,并記錄存儲(chǔ)路徑,用于后面郵件發(fā)送附件
save_path.append(url_to_pdf(url, title, targetPath, publish_date))
print('------pdf轉(zhuǎn)換保存成功!')
# 3、通過郵件將新生成的文件發(fā)送到自己的郵箱
user_name = '收件人名稱' # 可以寫自己的名字
email = '收件郵箱地址'
gzh_data = {
'gzh_name':gzh_name,
'publish_date':publish_date,
'save_path':save_path
}
send_email(user_name, email, gzh_data)
print('------郵件發(fā)送成功啦!')
隨便說說
我的五一也結(jié)束啦,祝大家明天周末愉快。
最重要的是明天是母親節(jié),在這里祝我的媽媽節(jié)日快樂,身體健康,其他的話單獨(dú)和媽媽說(嘿嘿),也祝天下所有母親節(jié)日快樂。
另外大家如果有什么類似需求,或者想要本文所有相代碼的ipynb文件,可以掃下方二維碼添加我的微信,查看朋友圈獲取。
歡迎大家進(jìn)行學(xué)習(xí)交流。
參考鏈接
wechatsogou:https://github.com/Chyroc/WechatSogou 二十次冪平臺(tái):https://www.ershicimi.com/ 博客園xuzifan:https://www.cnblogs.com/xuzifan/p/11121878.html wkhtmltopdf下載地址:https://wkhtmltopdf.org/downloads.html
掃碼即可加我微信
觀看朋友圈,獲取最新學(xué)習(xí)資源
學(xué)習(xí)更多: 整理了我開始分享學(xué)習(xí)筆記到現(xiàn)在超過250篇優(yōu)質(zhì)文章,涵蓋數(shù)據(jù)分析、爬蟲、機(jī)器學(xué)習(xí)等方面,別再說不知道該從哪開始,實(shí)戰(zhàn)哪里找了
“點(diǎn)贊”傳統(tǒng)美德不能丟 
