之所以想要抓取微信公众号的文章,是因为我想把孟岩公众号的文章打包整理为一个电子书,方便查看,统一阅读。微信公众号对于历史文章支持的很不好。卡片式的展示也很影响连续阅读的体验。再吐槽一下,公众号的banner风尚也是一个很鸡肋的存在,很是累赘。
- 首先根据网上的方法利用Fiddler获取文章列表,但是没有成功,以失败告终
- 使用文档导出助手,导出的文章是独立的pdf格式,epub格式需要客服手工处理,质量也不好保证
很多人可能不知道,微信是可以挂代理的。TG、TIM、QQ好像都是差不多的设计,差不多是IM工具标配了。
微信的反爬机制做的很好(后来我细想可能也不单是为了反爬),最终我也没找到可以批量获取公众号链接的方法。
网上查了很多资料,做了很多尝试,想自动抓取公众号的全部链接都没有成功,这个路堵得很死。这样我就利用手工点击的方式抓去了孟岩公众号的所有链接。好在公众号只有两百多篇文章,半个多小时也就手工抓完了。
最初尝试使用requests,无法爬取到文章内容。做了一些尝试后发现姿势不对。然后换用selenium爬取。立杆见影,成功了。但是又遇到了一个新问题,图片不能加载。这样在selenium中开始尝试自动化控制滚轮,强制刷新图片,这样可以了。
代码如下:
import os
import sys
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
#driver.set_window_size(1080,800)
action = ActionChains(driver)
def is_end():
pageHeight = driver.execute_script("return document.body.scrollHeight")
totalScrolledHeight = driver.execute_script("return window.pageYOffset + window.innerHeight")
# -1 is to make sure the rounding issues
print(pageHeight, totalScrolledHeight)
if((pageHeight-1)<=totalScrolledHeight):
return True
else:
return False
def scroll_down(cnt):
for i in range(cnt):
time.sleep(1)
# action.send_keys(Keys.PAGE_DOWN)
# action.perform()
driver.execute_script("window.scrollBy(0,500)")
if is_end():
print("it is end")
time.sleep(2)
break
else:
print("not end")
with open(sys.argv[1], 'r', encoding='utf-8') as fp:
for cnt, line in enumerate(fp):
#print("Line {}: {}".format(cnt, line.strip()))
driver.get(url=line)
time.sleep(0.5)
scroll_down(20)
time.sleep(0.5)
print(type(driver.title), driver.title)
with open("%03d.html"%cnt, 'w', encoding='utf-8') as f:
print(driver.page_source, file=f)
#break
# if cnt > 1:
# break
driver.close()
代码解释:
- 需要传递一个文件参数(sys.argv[1]),文件存储的内容为链接
- 要想运行需要安装本地安装chrome浏览器,并安装chromedriver(全局目录)
- 延时参数需要根据实际网络状况调整(不着急可以把全部参数加倍)
- python大法好
- 爬取到html之后可以再利用BS4进行抽取格式化
- 然后利用pandoc将html转为md格式并把图片下载到本地(用scapy代替pandoc应该也是可以的,pandoc更简单)
- 微信的html源码里面有不少注释存在,这个还是让我有些意外的,大概这个地方不用做的极致吧
- 如果可以快速获取公众号全部链接接,整个工具链就完备了(欢迎各位读者留言告知)