沪上烟雨化炎阳
城池高深针棉藏
敢问哪处温柔乡
当是量化破高墙
-
方法综述1
爬取公众号目前主流的方案主要有两种:
第一种是通过搜狗搜索微信公众号的页面去找到文章地址,再去爬取具体文章内容;
第二种是通过注册公众号然后通过公众号的搜索接口去查询到文章地址,然后再根据地址去爬文章内容。
通过搜狗搜索来做其实核心思路就是通过request模拟搜狗搜索公众号,然后解析搜索结果页面,再根据公众号主页地址爬虫,爬取文章明细信息,但是这里需要注意下,因为搜狗和腾讯之间的协议问题,只能显示最新的10条文章,没办法拿到所有的文章。
第二种方式的缺点就是要注册公众号通过腾讯认证,通过调用接口公众号查询接口,但是翻页需要通过selenium去模拟滑动翻页操作。
本文重点探究方法二的实现方案。
-
通过公众号获取2
强烈推荐参考2中的视频,目前网上各种教程其实源头就在这个视频。
如果大家都花点精力附上参考链接的化,网上的文字垃圾不需要这么多。
个人公众号可以插入其他公众号的文章,这就为爬虫开了一扇门。
-
获取cookies
对接口的调用需要先登录微信公众平台,因此就需要cookies,来实现模拟浏览器登录。
cookies的获取需要selenium模块。
模拟浏览器需要一个浏览器驱动,比如chromedriver3。
如下实现自动登录微信公众号,获取cookie并将其保存在本地文件cookie.txt
from selenium import webdriver import time from pprint import pprint import json user_account = "your own account" user_password = "your own passport" driver = webdriver.Chrome(executable_path= 'C:\Program Files (x86)\Google\Chrome\chromedriver.exe') # 如果路径在环境变量内部,可以不指定路径直接运行 driver.get('https://mp.weixin.qq.com') # 打开浏览器 time.sleep(2) # 清空帐号框中的内容 driver.find_element_by_xpath("/html/body/div[1]/div[2]/div[2]/div/div/form/div[1]/div[1]/div/span/input").clear() # 在帐号框填写用户名 driver.find_element_by_xpath("/html/body/div[1]/div[2]/div[2]/div/div/form/div[1]/div[1]/div/span/input").send_keys(user_account) time.sleep(2) # 清空密码框中的内容 driver.find_element_by_xpath("/html/body/div[1]/div[2]/div[2]/div/div/form/div[1]/div[2]/div/span/input").clear() # 在密码框填写密码 driver.find_element_by_xpath("/html/body/div[1]/div[2]/div[2]/div/div/form/div[1]/div[2]/div/span/input").send_keys(user_password) # 勾选记住账号 driver.find_element_by_xpath("/html/body/div[1]/div[2]/div[2]/div/div/form/div[3]/label/i").click() time.sleep(1) # 点击登录 driver.find_element_by_xpath("/html/body/div[1]/div[2]/div[2]/div/div/form/div[4]/a").click() time.sleep(15) # 延时,扫描二维码 # 取出cookie cookies = driver.get_cookies() cookie = {} # 从cookie中取出name for item in cookies: name = item.get('name') value = item.get('value') cookie[name] = value # 将键值对放入cookie pprint(cookie) # 规整打印 # 存储cookie备用 with open('cookie.txt', 'w', encoding= 'utf-8') as f: f.write(json.dumps(cookie))
-
获取文章url
从本地读取cookie,然后通过个人公众号的插入文章接口获取目标公众号的
# 本地读取cookie with open('cookie.txt', 'r', encoding='utf-8') as f: cookie = f.read() cookie = json.loads(cookie) # 初始页响应 response = requests.get('https://mp.weixin.qq.com', cookies= cookie) token = re.findall(r'token=(.*)', response.url)[0] url_searchbiz = "https://mp.weixin.qq.com/cgi-bin/searchbiz?" dict_search = { 'action': 'search_biz', 'token': token, 'lang': 'zh_CN', 'f': 'json', 'ajax': '1', 'random': '0.25803841235589453', 'query': query, # 目标公众号 'begin': '0', 'count': '5' } search_response = requests.get(url_searchbiz, cookies= cookie, params= dict_search) fakeid = search_response.json().get('list')[0].get('fakeid') # 翻页 dict_appmsg = { 'token': token, 'lang': 'zh_CN', 'f': 'json', 'ajax': '1', 'random': random.random(), # 0-1的随机数 'action': 'list_ex', 'begin': start_time, 'count': '5', 'query': '', 'fakeid': fakeid, 'type': '9' } url_appmsg = "https://mp.weixin.qq.com/cgi-bin/appmsg?" appmsg_response = requests.get(url_appmsg, cookies= cookie, params= dict_appmsg) # 处理翻页 page_num = int(int(appmsg_response.json().get('app_msg_cnt'))/5) page_num_temp = int(end_time) / 5 begin = 0 while page_num > 0: dict_appmsg = { 'token': token, 'lang': 'zh_CN', 'f': 'json', 'ajax': '1', 'random': random.random(), 'action': 'list_ex', 'begin': '{}'.format(str(begin)), 'count': '5', 'query': '', 'fakeid': fakeid, 'type': '9' } print("翻页", begin) appmsg_response = requests.get(url_appmsg, cookies= cookie, params= dict_appmsg) app_msg_list = appmsg_response.json().get('app_msg_list') title = [] link = [] for item in app_msg_list: item_title = item.get('title') item_link = item.get('link') print(item_title) print(item_link) title.append(item_title) link.append(item_link) page_num -= 1 begin = int(begin) begin += 5 print(title) print(link)
我们不能去跟专业人士比专业,此办法经常爬取200多条之后就被腾讯诊断为频次过高,好在我的目标是文章,可以把已经获取到的链接保存下来,通过正则表达式提取其中url,执行步骤3
-
从url获取文章正文
# 爬取目标url r = requests.get(url) # 解析 soup = BeautifulSoup(r.text) # 获取文章日期 date_file = soup.find_all('script') # 找到指定标签 date_file = str(date_file) patten_1 = re.compile('(\d{4}-\d{1,2}-\d{1,2})') # 匹配日期 date = patten_1.findall(date_file)[0] # 获取文章内容 data =soup.find_all('p') # 选取p标签内容 data_chi_str = str(data) # 将筛选内容转为字符串 # 选出所有中文字符 patten = re.compile("[\u4e00-\u9fa5]") # 匹配所有中文字符 chi_list = patten.findall(data_chi_str) text = ''.join(chi_list) print(text) file_name = '.'.join([date,'txt']) print(file_name, '文章获取并保存成功')
这一步比较简单,腾讯也没有刁难。
关于正则表达式的匹配:
-
-
爬取结果
feiweiwei, Python爬取微信公众号文章, Github, 2018.08 ↩︎
Quant_By_Python, 正则表达式匹配全部中文、日期YYYY-MM-DD、从txt中提取url, 2019.06 ↩︎
Quant_By_Python, Python正则表达式re模块高频用法, 2019.06 ↩︎