使用公众号自带的接口去抓取想要的信息,首先要在自己的公众号中对文章或者公众号进行查找,在数据包中解析出想要的信息,过程中最重要的几个难点:
- cookies:标识别登录信息
- token:个人标识
- fakeid:标识公众号
1. 调用接口查找文章
进入主页 -> 素材管理 -> 新建图文 -> 超链接 -> 查找文章
I. 素材管理
II. 新建图文
III. 超链接
IV. 查找文章
2. 抓取所有相关公众号信息
我们输入关键字并点击搜索后,右侧会出现相应的数据包,这里比较好找,选中xhr后只会出现唯一的数据包
I. 查看访问参数
选中它选择headers栏滑到最下方可以看到一系列的请求参数,比较重要的参数无非token、query(搜索关键字)、begin(开始的数值)、count(每页显示的数值),在headers中还能够看到数据的真实url,之后会向他发起请求
II. 查看数据包内容
在这里可以看到数据包内返回的所有内容,一般都是json格式,也可以查看一下是否与页面上看的的内容相对应,这里在返回数据的list列表中可以看到每个公众号的信息,包括fakeid(之后访问公众号文章会用到),公众号名称、公众号号码和总搜索量
III. 流程分析
我们通过模拟登陆获取到cookie后,访问主页获取到url上的token标识,通过向抓取到的数据包上面的真实url发送请求以及数据来获取相应信息,在返回的信息中,通过解析total判断总数量,改变begin的数值来执行翻页,最后将信息写入文件
class Public(metaclass=SingletonType):
def __init__(self, search_key, token, cookie):
self.search_key = search_key
self.url = 'https://mp.weixin.qq.com/cgi-bin/searchbiz?'
self.headers = {
'cookie': cookie,
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/74.0.3729.169 Safari/537.36'
}
self.data = {
'action': 'search_biz',
'token': token,
'lang': 'zh_CN',
'f': 'json',
'ajax': '1',
'random': '0.012103784566473319',
'query': self.search_key,
'count': '5'
}
def get_total(self):
self.data['begin'] = 0
content = requests.get(self.url, headers=self.headers, params=self.data).json()
total = content['total']
if total % 5:
return int(total / 5) + 1
else:
return int(total / 5)
def parse_public(self, num):
self.data['begin'] = num
content = requests.get(self.url, headers=self.headers, params=self.data).json()
return content
def get_data(self):
for num in range(0, self.get_total() + 1, 5):
for data in self.parse_public(num)['list']:
yield {
"name": data['nickname'],
"id": data['fakeid'],
'number': data['alias']
}
time.sleep(random.randint(1, 3))
def write_data(result, filename):
for data in result:
print(data)
with open(filename, 'a', encoding='utf-8') as f:
f.write(json.dumps(data, ensure_ascii=False) + '\n')
3. 抓取公众号下的文章
在上一步的操作后选定相应的公众号并执行抓包,可以看到新的数据包,包含其下的所有文章列表
I 抓包
II. 查看请求参数
很明显,这里就用到了之前我们所获取到的fakeid信息,其他的都和之前类似,query同样是搜索关键字,指定query后会返回相关搜索项,未指定则默认为空,返回默认的
II. 查看数据内容
III. 流程分析
通过模拟登陆后获取到cookie和token,fakeid可以自行获取,参考上一部分获取公众号信息的内容,然后向数据包的真实url发送请求,对返回的数据做解析,通过app_msg_cnt获取总量,更改begin值执行翻页,获取文章标题、创建时间(时间戳需要转为时间格式)、文章简述、文章链接等信息,最后执行写入文件操作
class Articls(metaclass=SingletonType):
def __init__(self, token, fakeid, cookie, search_key=""):
self.search_key = search_key
self.url = 'https://mp.weixin.qq.com/cgi-bin/appmsg?'
self.headers = {
'cookie': cookie,
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/74.0.3729.169 Safari/537.36',
'host': 'mp.weixin.qq.com',
'Connection': 'keep-alive',
'Accept': 'application/json, text/javascript, */*; q=0.01'
}
self.data = {
"token": token,
"lang": "zh_CN",
"f": "json",
"ajax": "1",
"action": "list_ex",
"count": "5",
"query": self.search_key,
"fakeid": fakeid,
"type": "9",
}
def parse_articles(self, num):
self.data['begin'] = num
content = requests.get(self.url, headers=self.headers, params=self.data).json()
return content
def get_total(self):
self.data['begin'] = 0
content = requests.get(self.url, headers=self.headers, params=self.data).json()
total = content['app_msg_cnt']
if total % 5:
return int(total / 5) + 1
else:
return int(total / 5)
@staticmethod
def convert_2_time(stamp):
return time.strftime("%Y-%m-%d", time.localtime(stamp))
def get_data(self):
if self.get_total():
for num in range(0, self.get_total() + 1, 5):
for data in self.parse_articles(num)['app_msg_list']:
yield {
"title": data['title'],
"create_time": self.convert_2_time(data['create_time']),
# 摘要
'digest': data['digest'],
'link': data['link']
}
time.sleep(random.randint(1, 3))
else:
print("No search item")
exit()
def write_data(result, filename):
for data in result:
print(data)
with open(filename, 'a', encoding='utf-8') as f:
f.write(json.dumps(data, ensure_ascii=False) + '\n')
4. 模拟登陆
具体操作流程我们都已经知道了,现在就缺两个东西,cookie和token,我们仔细观察首页,token简直随处可见,html代码,url中随处可见,我们就简单的从url中获取即可,cookie我们通过selenium登录后获取
I. cookies获取
通过selenium调用chrome浏览器传入用户名以及密码,点击登录后睡眠一定时间给用户扫码,当登录成功后再次访问主页并获取cookie写入文件(是否写入文件看个人喜好,返回也可以)
def login(username, passwd):
cookies = {}
driver = webdriver.Chrome() # 谷歌驱动
driver.get('https://mp.weixin.qq.com/')
# 用户名
driver.find_element_by_xpath('//input[@name="account"]').clear()
driver.find_element_by_xpath('//input[@name="account"]').send_keys(username)
driver.find_element_by_xpath('//input[@name="password"]').clear()
driver.find_element_by_xpath('//input[@name="password"]').send_keys(passwd)
# 登录
driver.find_element_by_xpath('//a[@class="btn_login"]').click()
time.sleep(20)
# 获取cookie
driver.get('https://mp.weixin.qq.com/')
time.sleep(5)
cookie_items = driver.get_cookies()
for cookie_item in cookie_items:
cookies[cookie_item['name']] = cookie_item['value']
with open('cookie.txt', 'w') as f:
f.write(json.dumps(cookies))
driver.close()
- 这里对cookie有一个处理,因为selenium获取到的cookie是如下格式的,需要在其中提取出name和value,如果是用requests访问,还需要将字典转为字符串,并且以’; '分割,别忘记;后面的空格
II. token获取
读取文件解析cookie对主页发起请求,获取到token后和cookie一起返回
def get_cookie_token():
url = 'https://mp.weixin.qq.com'
header = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/74.0.3729.169 Safari/537.36',
'host': 'mp.weixin.qq.com',
}
with open('cookie.txt', 'r', encoding='utf-8') as f:
cookie = f.read()
cookies = json.loads(cookie)
response = requests.get(url=url, cookies=cookies)
token = re.findall(r'token=(\d+)', str(response.url))[0]
result = []
for k, v in cookies.items():
result.append(k + '=' + v)
return "; ".join(result), token