python爬取微信公众号文章(包含文章内容和图片)

    之前虽然做过网页爬取,但微信爬取一直没做过,因为我一直不知道网页可以进微信公众平台,只用过微信客户端进微信公众号。既然可以通过网页进微信公众平台,那么爬取微信公众号文章就流程上就没太多难度了。

    自己在网上找的一些python爬虫文章不太好用,就亲自写了一套,包括详细的页面附图和代码注释,代码复制下来后可以直接运行,供需要的同行参考交流。  爬取微信公众号文章之前,需要先申请微信公众号,针对个人使用的订阅号就行。

    爬取微信公众号文章有两种思路:

   一种是通过搜狗浏览器爬取,因为微信公众平台为搜狗提供了访问接口。

  第二种种就是通过google或firefox浏览器来爬取,本篇文章只讲解第二种方式,但第一种方式也可以借鉴第二种方式的部分代码。

    1、通过调用谷歌或火狐浏览器驱动,模拟微信公众号登录,获取到cookies(里面包含登录身份的token值),将cookies保存到本地文件中,供以后面访问微信公众号时携带身份识别之用。

    页面如下:

 点击登录后跳出来扫描验证页面:

 

login.py文件代码如下:

# -!- coding: utf-8 -!-
from selenium import webdriver
import time
import json

#谷歌和火狐两种驱动人选一种即可
# 调用谷歌浏览器驱动   如果本地电脑未安装谷歌驱动,请网上下载
driver = webdriver.Chrome()
# 调用火狐浏览器驱动   如果本地电脑未安装火狐驱动,请网上下载
# driver = webdriver.Firefox()
driver.get("https://mp.weixin.qq.com/") # 微信公众平台网址
driver.find_element_by_name("account").clear()
driver.find_element_by_name("account").send_keys("[email protected]")  # 自己的微信公众号
time.sleep(2)
driver.find_element_by_name("password").clear()
driver.find_element_by_name("password").send_keys("*******")  # 自己的微信公众号密码
driver.find_element_by_class_name("icon_checkbox").click()

time.sleep(2)
driver.find_element_by_class_name("btn_login").click()
time.sleep(15)
#此时会弹出扫码页面,需要微信扫码
cookies = driver.get_cookies()  # 获取登录后的cookies
print(cookies)
cookie = {}
for items in cookies:
    cookie[items.get("name")] = items.get("value")
# 将cookies写入到本地文件,供以后程序访问公众号时携带作为身份识别用
with open('cookies.txt', "w") as file:
    #  写入转成字符串的字典
    file.write(json.dumps(cookie))

    2、扫码后进入公众号首页,点击左侧的素材管理,如下图:

3、点击完素材管理后进入如下界面,并点击新建图文素材:

4、点击完新建图文素材后,等待5~6秒,进入如下页面:

5、点击上图中紫色框处的链条标志,进入如下页面,选择查找文章,在公众号中输入要查询的公众号,并点击输入框右侧的放大镜查询标识,例如输入“共轨之家”(别想歪了哈,只是个介绍汽车维修资料的公众号哈):

6、选中搜索出来的符合要求的公众号(当然也可以用微信公众号的唯一id搜,例如:gongguizhijia),单击后进入公众号,可以看到该公众号下的文章,如下图:

7、此时要上代码了,先分析一下文章的分页和F12后可以看到的请求信息。

    (1)、我们看到总共53页,每页展示20条。

    (2)、F12查看请求方式,请求头如下图:

    (3)不断的点击不同页码,发现查询参数begin的值和页码的关系为:begin=(当前页-1)*5,count值始终为5,token值可以从浏览器中获取。

   8、爬取该公众号下的所有文章的名字、唯一表示、链接,保存到本地文件article_link中,供爬取文章页面用(此处微信有访问频率限制,具体多少没详细测,我连续访问32次后被限制访问,提醒我操作频繁)。

         get_article_link.py代码如下:

# -*- coding:utf-8 -*- 
import requests
import json
import re
import random
import time

with open("cookies.txt", "r") as file:
    cookie = file.read()
cookies = json.loads(cookie)
url = "https://mp.weixin.qq.com"
response = requests.get(url, cookies=cookies)
token = re.findall(r'token=(\d+)', str(response.url))[0]  # 从url中获取token
print(token)
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36",
    "Referer": "https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit_v2&action=edit&isNew=1&type=10&token="+token+"&lang=zh_CN",
    "Host": "mp.weixin.qq.com",
}
# requestUrl = "https://mp.weixin.qq.com/cgi-bin/searchbiz"
with open('article_link.txt', "w", encoding='utf-8') as file:
    for j in range(1, 53, 1):
        begin = (j-1)*5
        requestUrl = "https://mp.weixin.qq.com/cgi-bin/appmsg?token="+token+"&lang=zh_CN&f=json&ajax=1&random="+str(random.random())\
                     +"&action=list_ex&begin="+str(begin)+"&count=5&query=&fakeid=MzA3NDM2ODIzMQ%3D%3D&type=9"
        search_response = requests.get(requestUrl, cookies=cookies, headers=headers)
        re_text = search_response.json()
        print(re_text)
        list = re_text.get("app_msg_list")
        for i in list:
            file.write(i["aid"]+"<=====>"+i["title"]+"<=====>"+i["link"] + "\n")
            print(i["aid"]+"<=====>"+i["title"]+"<=====>"+i["link"])
        time.sleep(20)

9、获取到的链接保存格式为:

10、解析上一步获取到的文章链接,

download_article.py代码如下:

# -*- coding:utf-8 -*-

import json
import re
import time
from bs4 import BeautifulSoup
import requests
import os


# 保存页面到本地
def save_html(url_content,htmlDir,file_name):
    f = open(htmlDir+"\\"+file_name+'.html', 'wb')
    f.write(url_content.content)  # save to page.html
    f.close()
    return url_content


# 修改文件,将图片路径改为本地的路径
def update_file(old, new,htmlDir):
    with open(htmlDir+"\\"+file_name+'.html', encoding='utf-8') as f, open(htmlDir+"\\"+file_name+'_bak.html', 'w',
                                                        encoding='utf-8') as fw:  # 打开两个文件,原始文件用来读,另一个文件将修改的内容写入
        for line in f:  # 遍历每行,取出来的是字符串,因此可以用replace 方法替换
            new_line = line.replace(old, new)  # 逐行替换
            new_line = new_line.replace("data-src", "src")
            fw.write(new_line)  # 写入新文件
    os.remove(htmlDir+"\\"+file_name+'.html')  # 删除原始文件
    time.sleep(10)
    os.rename(htmlDir+"\\"+file_name+'_bak.html', htmlDir+"\\"+file_name+'.html')  # 修改新文件名, old -> new
    print('当前保存文件为:'+file_name+'.html')

# 保存图片到本地
def save_file_to_local(htmlDir,targetDir,search_response,domain):
    obj = BeautifulSoup(save_html(search_response,htmlDir,file_name).content, 'lxml')  # 后面是指定使用lxml解析,lxml解析速度比较快,容错高。
    imgs = obj.find_all('img')
    # 将页面上图片的链接加入list
    urls = []
    for img in imgs:
        if 'data-src' in str(img):
            urls.append(img['data-src'])
        elif 'src=""' in str(img):
            pass
        elif "src" not in str(img):
            pass
        else:
            urls.append(img['src'])
    # 遍历所有图片链接,将图片保存到本地指定文件夹,图片名字用0,1,2...
    i = 0
    for each_url in urls:  # 看下文章的图片有哪些格式,一一处理
        if each_url.startswith('//'):
            new_url = 'https:' + each_url
            r_pic = requests.get(new_url)
        elif each_url.startswith('/') and each_url.endswith('gif'):
            new_url = domain + each_url
            r_pic = requests.get(new_url)
        elif each_url.endswith('png') or each_url.endswith('jpg') or each_url.endswith('gif') or each_url.endswith('jpeg'):
            r_pic = requests.get(each_url)
        t = os.path.join(targetDir, str(i) + '.jpeg')  # 指定目录
        print('当前保存图片为:' + t)
        fw = open(t, 'wb')  # 指定绝对路径
        fw.write(r_pic.content)  # 保存图片到本地指定目录
        i += 1
        update_file(each_url, t, htmlDir)  # 将老的链接(有可能是相对链接)修改为本地的链接,这样本地打开整个html就能访问图片
        fw.close()
#下载html页面和图片
def save(search_response,file_name):
    htmlDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), file_name)
    targetDir = os.path.join(os.path.dirname(os.path.abspath(__file__)),file_name+'\imgs1')  # 图片保存的路径,eg,向前文件夹为'D:\Coding', 即图片保存在'D:\Coding\imgs1\'
    if not os.path.isdir(targetDir):  # 不存在创建路径
        os.makedirs(targetDir)
    domain = 'https://mp.weixin.qq.com/s'
    save_html(search_response, htmlDir,file_name)
    save_file_to_local(htmlDir, targetDir, search_response, domain)
# 获得登录所需cookies
with open("cookies.txt", "r") as file:
    cookie = file.read()
cookies = json.loads(cookie)
url = "https://mp.weixin.qq.com"
response = requests.get(url, cookies=cookies)
token = re.findall(r'token=(\d+)', str(response.url))[0]
print(token)
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36",
    "Referer": "https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit_v2&action=edit&isNew=1&type=10&token="+token+"&lang=zh_CN",
    "Host": "mp.weixin.qq.com",
}
f = open("article_link.txt", encoding='utf-8')   # 返回一个文件对象
line = f.readline()   # 调用文件的 readline()方法
for line in open("article_link.txt", encoding='UTF-8'):
    new_line = line.strip()
    line_list = new_line.split("<=====>")
    file_name = line_list[0]
    dir_name = line_list[1]
    requestUrl = line_list[2]
    search_response = requests.get(requestUrl, cookies=cookies, headers=headers)
    save(search_response,  file_name)
    print(file_name+"----------------下载完毕:"+dir_name+"----------------下载完毕:"+requestUrl)
    time.sleep(2)
file.close()

11、下载后文章效果:

12、选择了google、百度、火狐、ie、Edge五种浏览器测试效果,其中google、百度、Edge浏览器正常打开带图片的页面,firefox浏览器只有文字,没有图片,ie打不开页面。综上,该爬取效果基本能满足需要。

发布了20 篇原创文章 · 获赞 24 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_41267342/article/details/96729138