php中文网 | cnphp.com

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 564|回复: 0

Python爬取微信公众号内容

[复制链接]

3138

主题

3148

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

UID
1
威望
0
积分
7946
贡献
0
注册时间
2021-4-14
最后登录
2024-11-21
在线时间
763 小时
QQ
发表于 2022-5-16 20:49:10 | 显示全部楼层 |阅读模式
[mw_shl_code=python,true]# -*- coding: utf-8 -*-

from selenium import webdriver
from lxml import etree
import time
import json
import requests
import re
import random
import urllib.request as urllib2
import time
from scrapy import Selector
from docx import Document
from docx.shared import Inches
import requests
from docx.oxml.ns import qn
from docx.shared import Pt,RGBColor


#微信公众号账号
user="touchstone@touchstone100edu.com"
#公众号密码
password="YLMsz8888"
#设置要爬取的公众号列表
gzlist=['赫石少儿体能']

#登录微信公众号,获取登录之后的cookies信息,并保存到本地文本中
def weChat_login():
    #定义一个空的字典,存放cookies内容
    post={}

    #用webdriver启动谷歌浏览器
    print("启动浏览器,打开微信公众号登录界面")
    driver = webdriver.Chrome(executable_path='C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe')
    #打开微信公众号登录页面
    driver.get('https://mp.weixin.qq.com/')
    #等待5秒钟
    time.sleep(10)
    print("正在输入微信公众号登录账号和密码......")
    #清空账号框中的内容
    driver.find_element_by_name('account').clear()
    #自动填入登录用户名
    driver.find_element_by_name('account').send_keys(user)
    #清空密码框中的内容
    driver.find_element_by_name('password').clear()
    #自动填入登录密码
    driver.find_element_by_name('password').send_keys(password)

    # 在自动输完密码之后需要手动点一下记住我
    print("请在登录界面点击:记住账号")
    time.sleep(10)
    #自动点击登录按钮进行登录
    driver.find_element_by_class_name('btn_login').click()
    # 拿手机扫二维码!
    print("请拿手机扫码二维码登录公众号")
    time.sleep(10)
    print("登录成功")
    #重新载入公众号登录页,登录之后会显示公众号后台首页,从这个返回内容中获取cookies信息
    driver.get('https://mp.weixin.qq.com/')
    #获取cookies
   
    cookie_items = driver.get_cookies()

    #获取到的cookies是列表形式,将cookies转成json形式并存入本地名为cookie的文本中
    for cookie_item in cookie_items:
        print(cookie_item['value'])
        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("cookies信息已保存到本地")
   
def validateTitle(title):
    rstr = r"[\/\\\:\*\?\"\<\>\|]"  # '/ \ : * ? " < > |'
    new_title = re.sub(rstr, "_", title)  # 替换为下划线
    return new_title

   
def ljkh(html_str):  # 提取数据
    html = etree.HTML(html_str)
    content_list = []
    item = {}
    item["title"] = html.xpath("//*[@id=\"activity-name\"]/text()")
    item["title"] = [i.replace("\n", "").replace(" ", "") for i in item["title"]]
    item["laiyuan"] = html.xpath("//*[@id=\"js_name\"]/text()")
    item["laiyuan"] = [i.replace("\n", "").replace(" ", "") for i in item["laiyuan"]]
    item["other"] = html.xpath("//*[@id=\"js_content\"]//text()")
   
    content_list.append(item)
  
    return content_list

def parse_url(headers, url):  
    response = requests.get(url, headers=headers)
    return response.content.decode()
#爬取微信公众号文章,并存在本地文本中
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 ... mp;token=1849751598,从这里获取token信息
    response = requests.get(url=url, cookies=cookies)
    token = re.findall(r'token=(\d+)', str(response.url))[0]

    #搜索微信公众号的接口地址
    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)
    #获取文章总数
    max_num = appmsg_response.json().get('app_msg_cnt')
    #每页至少有5条,获取文章总的页数,爬取时需要分页爬
    num = int(int(max_num) / 5)
    #起始页begin参数,往后每页加5
    begin = 0
    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)

        #获取每一页文章的标题和链接地址,并写入本地文本中
        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')
         
                   # 解析url,获得html
            #html_str = parse_url(header,content_link)
            # 获取内容            
            # list转字符串
            get_biz_html(content_link)
         
            fileName=query+'.txt'
            with open(fileName,'a',encoding='utf-8') as fh:
                fh.write(content_title+":\n"+content_link+":\n")
        num -= 1
        begin = int(begin)
        begin+=5
        time.sleep(2)
header = {
    "Host": "mp.weixin.qq.com",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
    "Accept-Encoding": "gzip, deflate, br",
    "Connection": "keep-alive"
}

def get_biz_html(url):
    """
    获取公众号的页面
    :param url:
    :return:
    """
    res = requests.get(url=url,timeout=8,headers=header).text
    contents = Selector(text=res).css('#js_content')
    re_title = re.compile('property="og:title".*?content="(.*?)"',re.S)
    re_time = re.compile(',n="(.*?)",',re.S)
    re_img = re.compile('property="og:image".*?content="(.*?)".*?/>')
    re_des = re.compile('name="description".*?content="(.*?)".*?/>')
    try:
        #构建存储字典
        item = {}
        #公众号标题
        title = re.findall(re_title,res)[0].strip()
        #公众号作者
        source = Selector(text=res).css('#js_name::text').extract_first().strip()
        #公众号链接
        url = url
        #公众号发布时间
        news_time = re.findall(re_time,res)[0]
        if news_time:
            news_time=time.strftime(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(int(news_time))))
        #公众号封面
        newsImage = re.findall(re_img,res)[0].strip()
        try:
            newsDes = re.findall(re_des,res)[0].strip()
        except:
            newsDes = ''
        content = contents.extract_first()
        get_html_item(title,content,source,news_time)
    except Exception as e:
        print('[Exception]:'+str(e))
        pass

def get_html_item(title,contents,source,news_time):
    """
    将文章正文分段
    :param title:
    :param contents:
    :param source:
    :param news_time:
    :return:
    """
   
    content_list =[]
    content_set = set()
    contents = Selector(text=contents).css('#js_content *')
    item = {}
    for content in contents:
        # print(content.extract())

        if 'img' in content.extract():
            sub_txt = sub_html(content.extract())
            if sub_txt:
                sub_txt = sub_txt.strip()
                if sub_txt not in content_set:
                    content_set.add(sub_txt)
                    text = sub_txt.strip()
                    content_list.append({'text':text})
            img = content.css('img::attr(data-src)').extract_first()
            if img and img not in content_set:
                content_list.append({'img': img.strip()})
                content_set.add(img)
        else:
            sub_txt = sub_html(content.extract())
            if sub_txt:
                sub_txt = sub_txt.strip()
                if sub_txt not in content_set:
                    content_set.add(sub_txt)
                    text = sub_txt.strip()
                    content_list.append({'text': text})


    print('[INFO]:html_to_word')
    html_to_word(title,content_list,source,news_time)

def sub_html(text):
    """
    替换标签
    :param text:
    :return:
    """
    text = re.sub(re.compile('<.*?>'),'',text)
    return text
def html_to_word(title,contents,source,news_time):
    """
    写入wrod
    :param title:
    :param contents:
    :param source:
    :param news_time:
    :return:
    """
    document = Document()
    document.styles['Normal'].font.name = u'宋体'
    document.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), u'宋体')
    document.styles['Normal'].font.size = Pt(10.5)
    document.styles['Normal'].font.color.rgb = RGBColor(0, 0, 0)
    #添加标题,并设置级别,范围:0 至 9,默认为1
    document.add_heading(title, 0)
    #添加段落,文本可以包含制表符(\t)、换行符(\n)或回车符(\r)等
    document.add_paragraph('{source}                     {news_time} '.format(source=source,news_time=news_time)).italic = True
    for content in contents:
        try:
            img =content['img']
            requset_img(img)
            document.add_picture('1.jpg', width=Inches(5))
        except:
            text = content['text']
            document.add_paragraph(text)
    document.add_page_break()

    #保存.docx文档
    document.save('{}.docx'.format(validateTitle(title)))
    print('[INFO]:{}.docx is ok'.format(title))

    # document.save('{}.docx'.format(title))
    # print('{}.docx is ok'.format(title))

def img_parse(response):
    with open('1.jpg', 'wb') as img:
        img.write(response)

def requset_img(url):
    response = requests.get(url=url)
    img_parse(response.content)

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

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|php中文网 | cnphp.com ( 赣ICP备2021002321号-2 )

GMT+8, 2024-11-22 02:25 , Processed in 0.296493 second(s), 35 queries , Gzip On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

申明:本站所有资源皆搜集自网络,相关版权归版权持有人所有,如有侵权,请电邮(fiorkn@foxmail.com)告之,本站会尽快删除。

快速回复 返回顶部 返回列表