用 Python 抓取[每日看懂龙头股]公号文章保存成 HTML

本人是个股票爱好者,同时也是个Python学习者,最近学习Python的爬虫技术抓取自己喜欢的股票公众号的文章并保存起来,希望有缘者看到,如果你能按照我的文章成功执行,也许会有意向不到的收货。以下是我参考的链接,实际上下面我的实际操作过程。
https://mp.weixin.qq.com/s/jGjCfnGdxzK29FgC4E-_Cg
1.抓取的思路
下面三种思路我选择了第三种,第二种我也试了,失败。
1)通过手机和电脑相连,利用 Fiddler 抓包获取请求和返回报文,然后通过报文模拟请求实现批量下载。
2)通过搜狗浏览器或者用 wechatsogou 这个 Python 模块,去搜索公号后,实现批量下载。
3)通过公众号平台,这个需要你能登陆到公众号平台即可,剩下就比较简单。
2.抓取之前的准备工作
1)本机安装Python ,Python的安装方法,可以上网搜素一下,网上很多,笔者随便找了个一个。
https://www.jianshu.com/p/c389b2f2b04f

  1. 本人有一个公众号,如何申请公众号,也请上网搜索,笔者也搜索了一个,请参考
    https://www.jianshu.com/p/a1164d48dc2c?from=groupmessage
    3.言归正传,开始抓取公众号文章。
    1)获取 Cookie
    首先我们登陆到公众号平台,登陆成功后会跳转到公众号管理首页,如下图:
    image.png

    然后我们在当前页面打开浏览器开发者工具快捷键F12,刷新下页面,在网络里就能看到各种请求,在这里我们点开一个请求 url,然后就能看到下图网络请求信息,里面包含请求的 Cookie 信息。
    image.png

    接下来我们需要把 Cookie 信息复制下来转换成 Json 格式串保存到文本文件里,以供后面请求链接时使用。这里需要写一段 Python 代码进行处理,新建文件 gen_cookies.py 写入代码如下:
    image.png

    好了,将 Cookie 写入文件后,接下来就来说下在哪里可以找到某公号的文章链接。

获取文章链接

在公号管理平台首页点击左侧素材管理菜单,进入素材管理页面,然后点击右侧的新建图文素材按钮,如下图:

image

进入新建图文素材页面,然后点击这里的超链接:

image

在编辑超链接的弹出框里,点击选择其他公众号的连接:

image

在这里我们就能通过搜索,输入关键字搜索我们想要找到公众号,比如在这里我们搜索 "每日看懂龙头股",就能看到如下搜索结果:


image.png

然后点击第一个 每日看懂龙头股的公众号,在这里我们就能看到这个公众号历史发布过的所有文章:


image.png

我们看到这里文章每页只显示五篇,一共分了232页,现在我们再打开自带的开发者工具,然后在列表下面点下一页的按钮,在网络中会看到向服务发送了一个请求,我们分析下这个请求的参数。


image.png

通过请求参数,我们大概可以分析出参数的意义, begin 是从第几篇文章开始,count 是一次查出几篇,fakeId 对应这个公号的唯一 Id,token 是通过 Cookie 信息来获取的。好了,知道这些我们就可以用 Python 写段代码去遍历请求,新建文件 gzh_download.py,代码如下:
import datetime

import random
from pathlib import Path

from pathlib import Path
import requests
import json
import time
import re
from bs4 import BeautifulSoup
import os
from PIL import Image, ImageDraw, ImageFont
import shutil

import pdfkit

import wechatsogou

保存下载的 html 页面和图片

def save(search_response, html_dir, file_name):
# 保存 html 的位置
htmlDir = os.path.join(os.path.dirname(os.path.abspath(file)), html_dir)
# 保存图片的位置
targetDir = os.path.join(os.path.dirname(os.path.abspath(file)), html_dir + '/images')
# 不存在创建文件夹
if not os.path.isdir(targetDir):
os.makedirs(targetDir)
domain = 'https://mp.weixin.qq.com/s'
# 调用保存 html 方法
save_html(search_response, htmlDir, file_name)
# 调用保存图片方法
save_file_to_local(htmlDir, targetDir, search_response, domain, file_name)

保存图片到本地

def save_file_to_local(htmlDir, targetDir, search_response, domain, file_name):
# 使用lxml解析请求返回的页面
obj = BeautifulSoup(save_html(search_response, htmlDir, file_name).content, 'lxml')
# 找到有 img 标签的内容
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)
    time.sleep(random.randint(1, 2))
    # 创建指定目录
    t = os.path.join(targetDir, str(i) + '.jpeg')
    # t1要把图片存成相对路径,否则移动位置无法打开
    t1 = os.path.join('images', str(i) + '.jpeg')
    print('该文章共需处理--' + str(len(urls)) + '张图片,正在处理第' + str(i + 1) + '张……')
    # 指定绝对路径
    fw = open(t, 'wb')
    # 保存图片到本地指定目录
    fw.write(r_pic.content)

    i += 1
    # 将旧的链接或相对链接修改为直接访问本地图片
    update_file(each_url, t1, htmlDir, file_name)
    fw.close()
    # 给图片加水印
    fp = open(t, 'rb')
    im = Image.open(fp).convert('RGBA')  # 这里改为文件句柄
    barcode = random.choice([r'F:\File\个人\微信二维码.png', r'F:\File\个人\微信二维码.png'])
    logo = Image.open(barcode)
    txt = Image.new('RGBA', im.size, (0, 0, 0, 0))
    txt.paste(logo, (im.size[0] - logo.size[0], im.size[1] - logo.size[1]))
    fnt = ImageFont.truetype("c:/Windows/fonts/simkai.ttf", 20)
    d = ImageDraw.Draw(txt)
    d.text((im.size[0] - 250, im.size[1] - 80), u"WX:guduxin2020 整理", font=fnt, fill=(255, 255, 255, 255))
    Image.alpha_composite(im, txt).save(str(t).replace('jpeg', 'png'), 'png')

    fp.close()

    shutil.copyfile(str(t).replace('jpeg', 'png'), t)
    os.remove(str(t).replace('jpeg', 'png'))

保存 HTML 到本地

def save_html(url_content, htmlDir, file_name):
f = open(htmlDir + "/" + file_name + '.html', 'wb')
# 写入文件
f.write(url_content.content)
f.close()
return url_content

修改 HTML 文件,将图片的路径改为本地的路径

def update_file(old, new, htmlDir, file_name):
# 打开两个文件,原始文件用来读,另一个文件将修改的内容写入
with open(htmlDir + "/" + file_name + '.html', encoding='utf-8') as f, open(htmlDir + "/" + file_name + '_bak.html',
'w', encoding='utf-8') as fw:
# 遍历每行,用replace()方法替换路径
for line in f:
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(0.5)
# 修改新文件名为 html
os.rename(htmlDir + "/" + file_name + '_bak.html', htmlDir + "/" + file_name + '.html')

with open("F:\source\PYTHON\python-100-day-master\python-100-day-master\公众号文章保存\cookie.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]

token = re.findall(r'token=(\d+)', str(response.url))[0]
headers = {
"Host": "mp.weixin.qq.com",
"Referer": "https://mp.weixin.qq.com/cgi-bin/appmsg?t=media/appmsg_edit_v2&action=edit&isNew=1&type=10&token=1595906960&lang=zh_CN",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"
}

循环遍历前10页的文章

for j in range(1, 5, 1):
begin = (j - 1) * 5
# 请求当前页获取文章列表
requestUrl = "https://mp.weixin.qq.com/cgi-bin/appmsg?action=list_ex&begin=" + str(
begin) + "&count=5&fakeid=MzAxMDYxNDQ4NA==&type=9&query=&token=" + token + "&lang=zh_CN&f=json&ajax=1"
search_response = requests.get(requestUrl, cookies=cookies, headers=headers)
# MzU2NzEwMDc1MA== 爱在冰川
# MzAxMDYxNDQ4NA== 看懂龙头股
# MzIyMjAyMzkyNw==下注的快感
# Mzg5MzEyNzEwNQ==财联社
# MzI5ODc4Njc2Ng==盘口逻辑拆解

# 获取到返回列表 Json 信息
re_text = search_response.json()
list = re_text.get("app_msg_list")

if list is not None:
    # file_normal = open('公众号文章链接_平常1.txt', mode='a', encoding='utf-8')
    # file_saturday = open('公众号文章链接_周六1.txt', mode='a', encoding='utf-8')
    # 遍历当前页的文章列表
    for i in list:
        # 将文章链接转换 pdf 下载到当前目录
        tupTime = time.localtime(i["create_time"])  # 秒时间戳
        standardTime = time.strftime("%Y%m%d", tupTime)  # 转换Wie正常的时间
        title = i["title"]
        # print(i["link"] + "  " + i["title"] + " " + standardTime)
        # 目录名为标题名,目录下存放 html 和图片
        pat = r"(\xe2\x98\x85|\xe2\x97\x86)|(\[\d+-\d+-\d+\])"
        repat = re.compile(pat)
        # 特殊字符替换
        dir_name = repat.sub('_', i["title"])
        print(os.path.dirname(__file__))
        # if (os.path.exists(dir_name)):
        #     print('已经存在' + dir_name)
        #     continue
        dir_name = dir_name.replace(' ', '')
        dir_name = dir_name.replace(',', '')
        dir_name = dir_name.replace(':', '')
        dir_name = dir_name.replace('?', '')
        dir_name = dir_name.replace('?', '')
        dir_name = dir_name.replace('/', '_')
        dir_name = dir_name.replace('|', '_')
        dir_name = dir_name.replace('*', '_')
        # dir_name = i["title"].replace(' ', '').replace(':',)
        myfolder = Path(standardTime + '_' + dir_name)
        if myfolder.is_dir():
            print('已经存在' + dir_name)
            continue
        print("正在下载文章:" + dir_name)
        # 请求文章的url,获取文章内容
        response = requests.get(i["link"], cookies=cookies, headers=headers)

        # 保存文章到本地
        try:
            if str(i["title"]).__contains__('周六'):
                save(response, standardTime + '_' + dir_name,standardTime + '_' + dir_name)
            else:
                save(response, standardTime + '_' + dir_name, standardTime + '_' + dir_name)
        except Exception:
            # print('第d%页第d%篇文章错误' % (j - 1) % begin)
            print(('第{page}页第{count}篇文章{dir_name}错误' + str(Exception.args)).format(page=(j - 1), count=(begin),
                                                                                   dir_name=dir_name))
            continue
        # 将html文件转换为pdf文件
        # pdfkit.from_file(dir_name + "/" + i["aid"] + '.html', i["title"] + standardTime + '.pdf')
        # 重命名pdf文件名字

        # os.rename(dir_name + "/" + standardTime + '.html', dir_name + "/" + dir_name+standardTime + '.html')
        print('第{page}页第{count}篇文章{dir_name} 下载完成!'.format(page=str(j - 1), count=str(begin), dir_name=dir_name))
        # if str(i["title"]).__contains__('周六'):
        #     file_saturday.writelines(i["title"] + " " + standardTime + "\r\n' " + i["link"] + '\r\n')
        # else:
        #     file_normal.writelines(i["title"] + " " + standardTime + "\r\n' " + i["link"] + '\r\n')

        # 过快请求可能会被微信问候,这里进行10秒等待
        # time.sleep(1)

        # file_normal.close()
        # file_saturday.close()

本人的代码里还包含了一些自己很喜欢的公众号的代码,另外本人代码里还集成了下载的公众号文章的图片加水印的功能,防止别的人拿去涉及到版权问题。

总结

本文为大家介绍了如何通过分析公众号平台的功能,找到可以访问到每日看懂龙头股所有文章的链接,从而可以批量下载该公众号所有文章,由于下载并保存成pdf文件会出现错误,本人改成了使用html的形式,如果有兴趣你也可以试试。

源代码参考:
https://github.com/pitucre/gongzhonghao.git

相关免费文章我已经整理并放到网盘上了,大家可以去下载、
链接:https://pan.baidu.com/s/1dz7CMvSsgYvh6TytXZcStQ

提取码:sdbo

如果有任何疑问也可以加我qq:282104333 ,或者微信:guduxin2020

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353