公众号爬虫,仅仅 7 步实现|万字笔记

文章目录

    • 01 具体操作步骤
      • 1. 安装必要的库
      • 2. 导入库
      • 3. 准备中文字体
      • 4. 抓取网页内容
      • 5. 解析网页内容
      • 6. 生成PDF
      • 7. 主程序
    • 02 完整案例代码

如果想将公众号的文章转成 PDF 文件的话,非常简单,实现方式如下:

01 具体操作步骤

1. 安装必要的库

首先,你需要安装一些库,就像在做一个大项目时,你需要准备工具一样:

pip install selenium beautifulsoup4 reportlab requests

2. 导入库

想象一下,你在做一个大项目,首先你需要把所有的工具都拿出来放好:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup
import time
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from io import BytesIO
import requests

3. 准备中文字体

就像在画画前准备颜料一样,这里我们准备中文字体:

try:from reportlab.pdfbase import cidfontspdfmetrics.registerFont(cidfonts.UnicodeCIDFont('STSong-Light'))
except:print("无法加载中文字体,使用默认字体")

4. 抓取网页内容

这就像用一个机器人去网上抓取一个网页的内容:

def fetch_article_with_selenium(url):chrome_options = Options()chrome_options.add_argument("--headless")  # 让浏览器在后台运行driver = webdriver.Chrome(options=chrome_options)driver.get(url)# 等待页面加载wait = WebDriverWait(driver, 30)try:element = wait.until(EC.presence_of_element_located((By.TAG_NAME, "body")))# 模拟滚动到页面底部last_height = driver.execute_script("return document.body.scrollHeight")while True:driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")time.sleep(2)new_height = driver.execute_script("return document.body.scrollHeight")if new_height == last_height:breaklast_height = new_height# 等待所有图片加载images = driver.find_elements(By.TAG_NAME, "img")for img in images:WebDriverWait(driver, 10).until(lambda d: img.get_attribute('complete') == 'true')html_content = driver.page_source.encode('utf-8').decode('utf-8')print("页面内容获取成功")except Exception as e:print(f"页面加载失败: {e}")html_content = Nonedriver.quit()return html_content

5. 解析网页内容

就像从一大堆杂物中找出你需要的部分:

def parse_article_content(html):soup = BeautifulSoup(html, 'html.parser')content_divs = []content_divs.extend(soup.find_all('div', class_=lambda x: x and ('rich_media_content' in x or 'article-content' in x)))content_divs.extend(soup.find_all('div', class_=lambda x: x and ('content' in x or 'post-content' in x)))content_divs.extend(soup.find_all('article'))for div in content_divs:if div.find('p'):print("找到文章内容")return divbody = soup.find('body')if body:print("尝试解析整个body")return bodyprint("未找到文章内容")return None

6. 生成PDF

就像用一个打印机打印文档:

def text_to_pdf(div, output_filename):doc = SimpleDocTemplate(output_filename, pagesize=A4,rightMargin=72, leftMargin=72,topMargin=72, bottomMargin=18)Story = []styles = getSampleStyleSheet()heading_style = ParagraphStyle('Heading1', parent=styles['Heading1'], fontName='STSong-Light', fontSize=16, leading=20)normal_style = ParagraphStyle('Normal', parent=styles['Normal'], fontName='STSong-Light', fontSize=12, leading=16)for element in div.children:if element.name == 'p':p = Paragraph(element.get_text(strip=True), normal_style)Story.append(p)Story.append(Spacer(1, 12))  # 添加段落间距elif element.name in ['h1', 'h2', 'h3']:h = Paragraph(element.get_text(strip=True), heading_style)Story.append(h)Story.append(Spacer(1, 12))  # 添加标题后间距elif element.name == 'img':img_url = element.get('src')if img_url:response = requests.get(img_url)img = Image(BytesIO(response.content), width=element.get('width'), height=element.get('height'))Story.append(img)Story.append(Spacer(1, 12))  # 添加图片后间距elif element.name == 'br':Story.append(Spacer(1, 6))  # 添加换行间距if not Story:Story.append(Paragraph("无法从页面获取内容。", normal_style))doc.build(Story)

7. 主程序

就像一个指挥者,组织所有步骤:

def main():url = input("请输入文章的链接: ")html_content = fetch_article_with_selenium(url)if html_content:article_div = parse_article_content(html_content)if article_div:output_filename = "article.pdf"text_to_pdf(article_div, output_filename)print(f"文章已保存为PDF文件: {output_filename}")else:print("无法解析文章内容。")else:print("无法获取文章内容。")if __name__ == "__main__":main()

02 完整案例代码

注意:某些经过三方编辑平台格式化后的文章,可能无法抓取,不过你们可以继续深入研究。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup
import time
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from io import BytesIO
import requests
import logging# 设置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')# 使用系统默认中文字体
try:from reportlab.pdfbase import cidfontspdfmetrics.registerFont(cidfonts.UnicodeCIDFont('STSong-Light'))
except:try:from reportlab.pdfbase import cidfontspdfmetrics.registerFont(cidfonts.UnicodeCIDFont('HeiseiKakuGo-W5'))except:logging.warning("无法加载中文字体,使用默认字体")def fetch_article_with_selenium(url):chrome_options = Options()chrome_options.add_argument("--headless")driver = webdriver.Chrome(options=chrome_options)driver.get(url)# 等待页面加载wait = WebDriverWait(driver, 30)try:element = wait.until(EC.presence_of_element_located((By.TAG_NAME, "body")))# 模拟滚动到页面底部last_height = driver.execute_script("return document.body.scrollHeight")while True:driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")time.sleep(2)new_height = driver.execute_script("return document.body.scrollHeight")if new_height == last_height:breaklast_height = new_height# 等待所有图片加载images = driver.find_elements(By.TAG_NAME, "img")for img in images:WebDriverWait(driver, 10).until(lambda d: img.get_attribute('complete') == 'true')html_content = driver.page_source.encode('utf-8').decode('utf-8')logging.info("页面内容获取成功")except Exception as e:logging.error(f"页面加载失败: {e}")html_content = Nonedriver.quit()return html_contentdef parse_article_content(html):soup = BeautifulSoup(html, 'html.parser')# 尝试多种可能的HTML结构content_divs = []content_divs.extend(soup.find_all('div', class_=lambda x: x and ('rich_media_content' in x or 'article-content' in x)))content_divs.extend(soup.find_all('div', class_=lambda x: x and ('content' in x or 'post-content' in x)))content_divs.extend(soup.find_all('article'))for div in content_divs:if div.find('p') or div.find('h1') or div.find('h2') or div.find('h3'):logging.info("找到文章内容")return div# 如果以上都失败,尝试解析整个bodybody = soup.find('body')if body:logging.info("尝试解析整个body")return bodylogging.warning("未找到文章内容")return Nonedef text_to_pdf(div, output_filename):doc = SimpleDocTemplate(output_filename, pagesize=A4,rightMargin=72, leftMargin=72,topMargin=72, bottomMargin=18)Story = []# 获取所有样式表styles = getSampleStyleSheet()# 创建新的样式对象heading_style = ParagraphStyle('Heading1', parent=styles['Heading1'], fontName='STSong-Light', fontSize=16, leading=20)normal_style = ParagraphStyle('Normal', parent=styles['Normal'], fontName='STSong-Light', fontSize=12, leading=16)# 遍历 div 中的所有元素for element in div.children:if element.name == 'p':# 段落p = Paragraph(element.get_text(strip=True), normal_style)Story.append(p)Story.append(Spacer(1, 12))  # 添加段落间距elif element.name in ['h1', 'h2', 'h3']:# 标题h = Paragraph(element.get_text(strip=True), heading_style)Story.append(h)Story.append(Spacer(1, 12))  # 添加标题后间距elif element.name == 'img':# 图片处理img_url = element.get('src')if img_url:try:response = requests.get(img_url)img = Image(BytesIO(response.content), width=element.get('width'), height=element.get('height'))Story.append(img)Story.append(Spacer(1, 12))  # 添加图片后间距except Exception as e:logging.error(f"无法加载图片 {img_url}: {e}")elif element.name == 'br':Story.append(Spacer(1, 6))  # 添加换行间距# 确保至少有一个段落if not Story:Story.append(Paragraph("无法从页面获取内容。", normal_style))doc.build(Story)def main():url = input("请输入文章的链接: ")html_content = fetch_article_with_selenium(url)if html_content:article_div = parse_article_content(html_content)if article_div:output_filename = "article.pdf"text_to_pdf(article_div, output_filename)logging.info(f"文章已保存为PDF文件: {output_filename}")else:logging.error("无法解析文章内容。")else:logging.error("无法获取文章内容。")if __name__ == "__main__":main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/425288.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

研1日记12

1. 改19->10 2. 学习数据不平衡问题 1. 欠采样 合并两个样本数据 两种方式 1. 按原分布比例划分。sklearn中train_test_split里,参数stratify含义解析_traintestsplit参数stratify-CSDN博客 3.刘二大人 卷积操作 待看论文: 刘老师指导&#xff1a…

用于稀疏自适应深度细化的掩码空间传播网络 CVPR2024

目录 Masked Spatial Propagation Network for Sparsity-Adaptive Depth Refinement (CVPR 2024)用于稀疏自适应深度细化的掩码空间传播网络1 介绍2 算法流程2.1 问题建模2.2 Guidance Network2.3 MSPN 模块 3 实验结果3.1 稀疏度自适应深度细化对比试验…

图论篇--代码随想录算法训练营第六十一天打卡| Floyd 算法,A*算法

Floyd 算法(求多源汇最短路) 题目链接:97. 小明逛公园 题目描述: 小明喜欢去公园散步,公园内布置了许多的景点,相互之间通过小路连接,小明希望在观看景点的同时,能够节省体力&…

计算机二级office操作技巧——Excel篇

文章目录 函数公式总结写在前面五大基本函数sum求和函数average求平均函数max求最大值函数min求最小值函数count求个数函数 rank排名函数if逻辑判断函数条件求个数函数countif单条件求个数函数countifs多条件求个数函数 条件求和函数sumifs多条件求和函数sumproduct乘积求和函数…

算法刷题[比较两个字符串的最大公字符串(滑动窗口实现)]

题目&#xff1a;编程实现&#xff1a;找出两个字符串中最大公共子字符串,如"abccade","dgcadde"的最大子串为"cad" 代码如下所示&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #inclu…

C语言实现贪吃蛇小游戏

✅博客主页:爆打维c-CSDN博客​​​​​​ &#x1f43e; &#x1f539;分享c语言知识及代码 &#x1f43e; 目录 游戏展示视频 一、项目准备工作 二、功能实现分析 1.游戏开始 a.设置本地化、创建窗口、标题 b.隐藏光标,封装定位光标的函数 c.打印欢迎界面及提示信息 …

网盘隐私照片泄露?教你如何保护自己的隐私照片!

网盘内的隐私照片 好兄弟最近遇到了一个困难&#xff1a;“我之前一直都是把照片存在网盘里面的&#xff0c;但是最近听说了某网盘的照片泄露了&#xff0c;自己的生活照啊&#xff0c;私密照啊都被人看光了&#xff0c;这太可怕了&#xff01;我现在也很担心自己的网盘上照片…

2021高教社杯全国大学生数学建模竞赛C题 Python代码演示

目录 问题一1.1 根据附件 1&#xff0c;对 402 家供应商的供货特征进行量化分析计算供货特征数据标准化对正向指标归一化对负向指标归一化 1.2 建立反映保障企业生产重要性的数学模型熵权法熵权法-TOPSISAHP 1.3 在此基础上确定 50 家最重要的供应商&#xff0c;并在论文中列表…

钢轨缺陷检测-目标检测数据集(包括VOC格式、YOLO格式)

钢轨缺陷检测-目标检测数据集&#xff08;包括VOC格式、YOLO格式&#xff09; 数据集&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1h7Dc0MiiRgtd7524cBUOFQ?pwdfr9y 提取码&#xff1a;fr9y 数据集信息介绍&#xff1a; 共有 1493 张图像和一一对应的标注文件 标…

Neo4j入门案例:三星堆

创建一个关于三星堆的知识图谱可以是一个非常有趣的项目&#xff0c;它可以帮助理解如何使用Neo4j来存储和查询复杂的关系数据。三星堆文化以其独特的青铜器、金器和其他文物而闻名&#xff0c;这为我们提供了一个丰富的历史背景来构建知识图谱。 数据模型定义 实体类型&#…

RTMP直播播放器的几种选择

如何选择RTMP播放器&#xff1f; 在选择RTMP播放器时&#xff0c;需要综合考虑多个因素&#xff0c;以确保选择的播放器能够满足实际需求并提供良好的用户体验。以下是一些选择RTMP播放器的建议&#xff1a; 1. 功能需求 低延迟&#xff1a;对于直播场景&#xff0c;低延迟是…

解读 Java 经典巨著《Effective Java》90条编程法则,第5条:优先考虑依赖注入来引用资源

【前言】欢迎订阅【解读《Effective Java》】系列专栏 《Effective Java》是 Java 开发领域的经典著作&#xff0c;作者 Joshua Bloch 以丰富的经验和深入的知识&#xff0c;全面探讨了 Java 编程中的最佳实践。这本书被公认为 Java 开发者的必读经典&#xff0c;对提升编码技…

STM32巡回研讨会总结(2024)

前言 本次ST公司可以说是推出了7大方面&#xff0c;几乎可以说是覆盖到了目前生活中的方方面面&#xff0c;下面总结下我的感受。无线类 支持多种调制模式&#xff08;LoRa、(G)FSK、(G)MSK 和 BPSK&#xff09;满足工业和消费物联网 (IoT) 中各种低功耗广域网 (LPWAN) 无线应…

MelosBoom:解锁数据价值的新纪元

在当今的数字时代&#xff0c;数据被誉为“新的石油”&#xff0c;但用户在传统的Web2环境中&#xff0c;往往无法真正享受到自己贡献数据的价值。大型互联网公司通过集中化的系统和算法&#xff0c;垄断了数据的使用权&#xff0c;并从中获取巨大的商业利益&#xff0c;而数据…

计算机三级网络技术总结(一)

RPR环中每一个节点都执行SRP公平算法IEEE 802.11a和g将传输速率提高到54Mbps一个BGP发言人与其他自治系统中的BGP发言人要交换路由信息就要先建立TCP连接在一个区域内的路由器数一般不超过200个进入接口配置模式&#xff1a;Router(config)#interface <接口名> 封装ppp协…

Qt 实现自定义截图工具

目录 Qt 实现自定义截图工具实现效果图PrintScreen 类介绍PrintScreen 类的主要特性 逐步实现第一步&#xff1a;类定义第二步&#xff1a;初始化截图窗口第三步&#xff1a;处理鼠标事件第四步&#xff1a;计算截图区域第五步&#xff1a;捕获和保存图像 完整代码PrintScreen.…

WLAN实验简述

一&#xff1a;配置生产AP1上级接入层交换机LSW3 sys [Huawei]sysname LSW3 [LSW3]undo info-center enable [LSW3]vlan batch 10 100 [LSW3]int g0/0/2 [LSW3-GigabitEthernet0/0/2]port link-type trunk [LSW3-GigabitEthernet0/0/2]port trunk allow-pass vlan 10 100 [LSW…

Java企业面试题3

1. break和continue的作用(智*图) break&#xff1a;用于完全退出一个循环&#xff08;如 for, while&#xff09;或一个 switch 语句。当在循环体内遇到 break 语句时&#xff0c;程序会立即跳出当前循环体&#xff0c;继续执行循环之后的代码。continue&#xff1a;用于跳过…

STM32 的 CAN 通讯全攻略

目录 一、CAN 通讯概述 二、 CAN 通讯原理 1.ISO11898 标准下的物理层特征 2.CAN 协议的帧类型 3. 总线仲裁介绍 4.位时序 5.STM32 CAN 控制器简介 6.标识符筛选器 三、软件设计 1.发送流程 1.1初始化 CAN 控制器 1.2准备发送数据 1.3 将数据填充到发送缓冲区 1.4…

Vue.js入门系列(二十九):深入理解编程式路由导航、路由组件缓存与路由守卫

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…