Python爬取微信公众号文章、点赞数

时间:2024-05-20 11:50:35

代码还是热乎的,只要你细心一步步的慢慢调试,绝壁没问题

前期准备

  1. 订阅号;
  2. Python;
  3. Fiddler;
  4. 微信账号;

流程

  1. 使用用微信公众号生成cookie
  2. 使用Fiddler抓取微信公众号数据, 获取阅读数
  3. 通过cookie请求公众号获取文章,再使用Fiddler抓取的数据获取阅读数
  4. 整理数据写入到数据库

效果

  1. 平均20s可爬取一篇文章。为了微信号、订阅号的安全 时间间隔长一点
  2. 可按日期爬取文章。
  3. 视频文章无法爬取。当然了代码优化优化应该也是可以的
  4. 订阅号会出现 搜索文章限制问题。换一个订阅号解决

操作

操作

  1. 获取订阅号Cookie
    1.1、基于Python调用chromedriver.exe, 打开URL
    1.2、输入账号、密码
    1.3、手动扫码
    1.4、生成cookie.txt 文件, 包含cookie信息
    Python爬取微信公众号文章、点赞数
  2. Fiddler抓取微信客户端公众号请求数据, 获取阅读量
    需要获取req_id 、 pass_ticket 、 appmsg_tojen、cookie 和user-agent
    Python爬取微信公众号文章、点赞数
    2、1 电脑登录微信(PC版)
    2、2 关注需要爬取的公众号
    2、3 设置Fiddler 并保存配置
    Python爬取微信公众号文章、点赞数
    微信客户端请求公众号文章, fiddler抓取到的数据req_id 、 pass_ticket 、 appmsg_tojen
    Python爬取微信公众号文章、点赞数
    微信客户端请求公众号文章, fiddler抓取到的数据cookie 和user-agent
    Python爬取微信公众号文章、点赞数
    最后恢复Fiddler的配置,会报错的
    Python爬取微信公众号文章、点赞数
    END!!!前面的获取工作就结束了…

一、获取cookie

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

import time
import json
from selenium import webdriver
import sys
sys.path.append('/path/to/your/module')

post = {}

driver = webdriver.Chrome(executable_path="chromedriver.exe")
driver.get('https://mp.weixin.qq.com')
time.sleep(2)

driver.find_element_by_name('account').clear()
driver.find_element_by_name('account').send_keys('订阅号账号')
driver.find_element_by_name('password').clear()
driver.find_element_by_name('password').send_keys('订阅号密码')

# 自动输入密码后点击记住密码
time.sleep(5)
driver.find_element_by_xpath("./*//a[@class='btn_login']").click()
# 扫码
time.sleep(20)
driver.get('https://mp.weixin.qq.com')
cookie_items = driver.get_cookies()
for cookie_item in cookie_items:
    post[cookie_item['name']] = cookie_item['value']
cookie_str = json.dumps(post)
with open('cookie.txt', 'w+', encoding='utf-8') as f:
    f.write(cookie_str)
    print('cookie write ok ...')

二、获取文章数据(文章列表写入数据库)
Python爬取微信公众号文章、点赞数

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

import time, datetime
import json
import requests
import re
import random
import MySQLdb

#设置要爬取的公众号列表
gzlist=['rmrbwx']

# 打开数据库连接
db = MySQLdb.connect("localhost", "root", "123456", "wechat_reptile_data", charset='utf8' )
# 使用cursor()方法获取操作游标
cursor = db.cursor()

# 获取阅读数和点赞数
def getMoreInfo(link):
    # 获得mid,_biz,idx,sn 这几个在link中的信息
    mid = link.split("&")[1].split("=")[1]
    idx = link.split("&")[2].split("=")[1]
    sn = link.split("&")[3].split("=")[1]
    _biz = link.split("&")[0].split("_biz=")[1]
    # fillder 中取得一些不变得信息
    req_id = "1412dd0hgEJ111EjE5kNKEXT"
    pass_ticket = "ZSq589XK234UBgaq5lTGXvP3gd9epp4Dwz0S2CFY7niZksXYfSig01Sr6cF8mr%252Bi"
    appmsg_token = "1008_ZZS61aEhRBKbADqokb3543YvuzLiKdSCns3myC95eqfZTY105aAMiu4CymM9Khe8ZjxI7CP8p4nzFVF5e6fy"

    # 目标url
    url = "http://mp.weixin.qq.com/mp/getappmsgext"
    # 添加Cookie避免登陆操作,这里的"User-Agent"最好为手机浏览器的标识
    phoneCookie = "rewardsn=; wxuin=81135434139; devicetype=Windows10; version=62060739; lang=zh_CN; pass_ticket=ZSq589XK9FkUBgaq5lTGXvP3gd54354Dwz0S2CFY7niZksXYfSig01Sr6cF8mr+i; wap_sid2=CIvC8IIDElxzNU04MzhjSkxXTHJ3YVBmRTRoY2g1V01Qc1BVYmZLNG5sOEZwUmZwUkcyYXFlTVZ1YVpiWk9wSUZBN1p6ZmVaMkQyM2pzME5XeEtsdW1SenZuLTBOZkFEQUFBfjDOlOnmBTgNQAE=; wxtokenkey=777"
    headers = {
        "Cookie": phoneCookie,
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 MicroMessenger/6.5.2.501 NetType/WIFI WindowsWechat QBCore/3.43.1021.400 QQBrowser/9.0.2524.400"
    }
    # 添加data,`req_id`、`pass_ticket`分别对应文章的信息,从fiddler复制即可。
    data = {
        "is_only_read": "1",
        "req_id": req_id,
        "pass_ticket": pass_ticket,
        "is_temp_url": "0",
    }

    params = {
        "__biz": _biz,
        "mid": mid,
        "sn": sn,
        "idx": idx,
        "key": "777",
        "pass_ticket": pass_ticket,
        "appmsg_token": appmsg_token,
        "uin": "777",
        "wxtoken": "777"
    }

    # 使用post方法进行提交
    content = requests.post(url, headers=headers, data=data, params=params).json()
    # 提取其中的阅读数和点赞数
    readNum = content["appmsgstat"]["read_num"]
    likeNum = content["appmsgstat"]["like_num"]

    # 歇10s,防止被封
    time.sleep(15)
    return readNum, likeNum

#爬取微信公众号文章,并存在本地文本中
def get_content(query):
    #query为要爬取的公众号名称
    #公众号主页
    url = 'https://mp.weixin.qq.com'
    #设置headers
    header = {
        "HOST": "mp.weixin.qq.com",
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0"
        }

    #读取上一步获取到的cookies
    with open('cookie.txt', 'r', encoding='utf-8') as f:
        cookie = f.read()
    cookies = json.loads(cookie)
    #登录之后的微信公众号首页url变化为:https://mp.weixin.qq.com/cgi-bin/home?t=home/index&lang=zh_CN&token=1849751598,从这里获取token信息
    response = requests.get(url=url, cookies=cookies)
    token = re.findall(r'token=(\d+)', str(response.url))[0]
    time.sleep(2)

    #搜索微信公众号的接口地址
    search_url = 'https://mp.weixin.qq.com/cgi-bin/searchbiz?'
    #搜索微信公众号接口需要传入的参数,有三个变量:微信公众号token、随机数random、搜索的微信公众号名字
    query_id = {
        'action': 'search_biz',
        'token' : token,
        'lang': 'zh_CN',
        'f': 'json',
        'ajax': '1',
        'random': random.random(),
        'query': query,
        'begin': '0',
        'count': '5'
        }
    #打开搜索微信公众号接口地址,需要传入相关参数信息如:cookies、params、headers
    search_response = requests.get(search_url, cookies=cookies, headers=header, params=query_id)
    #取搜索结果中的第一个公众号
    lists = search_response.json().get('list')[0]
    #获取这个公众号的fakeid,后面爬取公众号文章需要此字段
    fakeid = lists.get('fakeid')

    #微信公众号文章接口地址
    appmsg_url = 'https://mp.weixin.qq.com/cgi-bin/appmsg?'
    #搜索文章需要传入几个参数:登录的公众号token、要爬取文章的公众号fakeid、随机数random
    query_id_data = {
        'token': token,
        'lang': 'zh_CN',
        'f': 'json',
        'ajax': '1',
        'random': random.random(),
        'action': 'list_ex',
        'begin': '0',#不同页,此参数变化,变化规则为每页加5
        'count': '5',
        'query': '',
        'fakeid': fakeid,
        'type': '9'
        }
    #打开搜索的微信公众号文章列表页
    appmsg_response = requests.get(appmsg_url, cookies=cookies, headers=header, params=query_id_data)
    #获取文章总数
    if appmsg_response.json().get('base_resp').get('ret') == 200013:
        print('搜索公众号文章操作频繁!!!')
    max_num = appmsg_response.json().get('app_msg_cnt')

    #每页至少有5条,获取文章总的页数,爬取时需要分页爬
    num = int(int(max_num) / 5)
    #起始页begin参数,往后每页加5
    begin = 135 #根据内容自定义
    while num + 1 > 0 :
        query_id_data = {
            '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)
        time.sleep(5)

        #获取每一页文章的标题和链接地址,并写入本地文本中
        query_fakeid_response = requests.get(appmsg_url, cookies=cookies, headers=header, params=query_id_data)
        fakeid_list = query_fakeid_response.json().get('app_msg_list')

        for item in fakeid_list:
            content_link=item.get('link')
            content_title=item.get('title')
            update_time=item.get('update_time')
            timeArray = time.localtime(update_time)
            DataTime = time.strftime("%Y%m%d", timeArray)
            print(DataTime)
            Yearsmonth = time.strftime("%Y%m", timeArray)
            if Yearsmonth == '201903' or Yearsmonth == '201904':
                # 阅读数 点赞数
                readNum, likeNum = getMoreInfo(item['link'])
                print(readNum, likeNum)

                # SQL 插入语句
                sql = """INSERT INTO `wechat_urls` (`title`, `url`, `data_date`, `gzname`, `read_num`, `like_num`) VALUES ('""" + content_title + """', '""" + content_link+ """', '""" + DataTime+ """', '""" + query+ """', '""" + str(readNum)+ """', '""" + str(likeNum)+ """');"""
                try:
                    # 执行sql语句
                    print(sql)
                    cursor.execute(sql)
                    # 提交到数据库执行
                    db.commit()
                except:
                    # Rollback in case there is any error
                    db.rollback()
            time.sleep(1)
        num -= 1
        begin = int(begin)
        begin+=5
        time.sleep(3)

        # 关闭数据库连接
        # db.close()

if __name__=='__main__':
    try:
        #登录之后,通过微信公众号后台提供的微信公众号文章接口爬取文章
        for query in gzlist:
            #爬取微信公众号文章,并存在本地文本中
            print("开始爬取公众号:"+query)
            get_content(query)
            print("爬取完成")
    except Exception as e:
        print(str(e))

console日志
Python爬取微信公众号文章、点赞数

三、读取URL列表, 文章数据写入数据库

from urllib.request import urlopen
import MySQLdb
import requests
from pyquery import PyQuery as pq
import time, datetime

# 打开数据库连接
db = MySQLdb.connect("localhost", "root", "123456", "wechat_reptile_data", charset='utf8' )
# 使用cursor()方法获取操作游标
cursor = db.cursor()

# 写入数据
def insert_contents(title, url, data_date, gzname, read_num, like_num):
    # 抓取页码内容,返回响应对象
    response = requests.get(url)
    response.encoding = 'utf-8'
    # 将html构建为Xpath模式
    doc = pq(response.text)
    js_content = doc('#js_content').text()
    # SQL 插入语句
    sql = """INSERT INTO `wechat_reptile_data`.`wechat_datas` (`title`, `content`, `gzh`, `data_date`, `read_num`, `like_num`) VALUES ('""" + title + """', '""" + js_content + """', '""" + gzname + """', '""" + data_date + """', '""" + str(read_num) + """', '""" + str(like_num) + """');"""

    try:
        # 执行sql语句
        print('===>>>', data_date+' : '+gzname)
        cursor.execute(sql)
        # 提交到数据库执行
        db.commit()
    except:
        # Rollback in case there is any error
        db.rollback()
    time.sleep(1)

# 更新数据
def update_contents(title, url, data_date, gzname):
    # SQL 更新语句
    sql = """UPDATE wechat_urls SET state = '1' WHERE title = '"""+title+"""' AND data_date = '"""+data_date+"""' AND gzname = '"""+gzname+"""'"""
    try:
        # 执行SQL语句
        cursor.execute(sql)
        # 提交到数据库执行
        db.commit()
    except:
        # 发生错误时回滚
        db.rollback()
    time.sleep(1)


# SQL 查询语句
sql = "select * from wechat_urls where state='0';"
try:
   # 执行SQL语句
   cursor.execute(sql)
   # 获取所有记录列表
   results = cursor.fetchall()
   for row in results:
       title = row[0]
       url = row[1]
       data_date = row[2]
       gzname = row[3]
       read_num = row[4]
       like_num = row[5]
       insert_contents(title, url, data_date, gzname, read_num, like_num)
       update_contents(title, url, data_date, gzname)
except:
   print("Error: unable to fecth data")




代码是东拼西凑写出来的,时间紧任务重代码还没来得及优化…, 各位大牛们见谅了
哪位兄弟给代码优化了记得@我一下,我拷贝一份