我之前每每发布笔记都用csv纯文本记录,一个机缘巧得文章列表api实现在线整理自已的文章阅读量数据。
(笔记模板由python脚本于2025年01月10日 18:48:25创建,本篇笔记适合喜欢钻牛角尖的coder翻阅)
-
Python官网:https://www.python.org/
-
Free:大咖免费“圣经”教程《 python 完全自学教程》,不仅仅是基础那么简单……
地址:https://lqpybook.readthedocs.io/
自学并不是什么神秘的东西,一个人一辈子自学的时间总是比在学校学习的时间长,没有老师的时候总是比有老师的时候多。
—— 华罗庚
-
您,可以在评论区书写任何想法 -
(我将在看到的第一时间回应) - 点击这里回转《我的2024》
本文质量分:
本文地址: https://blog.csdn.net/m0_57158496/article/details/145063820
CSDN质量分查询入口:http://www.csdn.net/qc
- ◆ 手写id到在线捕获
- 1、前言
- 2、运行效果
- 2、代码导读
- 2.1 导入模块
- 2.2 基础变量设置
- 2.3 功能模块定义
- 2.4 主程序逻辑
- 2.5 结束和输出
- 2.6 注意事项
- 3、完整源码(Python)
◆ 手写id到在线捕获
1、前言
在记csdn的第二年(也就是2022下半年),开始习惯在发布后用手工csv记录id等相关数据的习惯,23年可以curl读取线上笔记源码文本后,就尝试re.findall文章阅读数等实时数据,无聊时我可以随心看看“庄稼地的长势”。
一个csdn个人博客文章列表的api机缘获悉,让想看到文章阅读量时,可以直接从csdn官方文章列表页面提取,走出我每篇博文html源码文本查阅阅读量的“原始生活”。💪💪👏👏
初始源码(初稿)
#!/usr/bin/env python3
print() # 打印空行
print(f"{f' 程序正在加载工具…… ':-^34}", end='\r')
from urllib import request
from urllib import error
from re import compile
from re import DOTALL
from time import time
# Base Var #
START = time()
path = '/sdcard/Documents/csdn/temp/'
usrname = 'm0_57158496'
url_base = f"https://blog.csdn.net/{usrname}/article/"
pattern = r'''<div class="article-item-box csdn-tracking-statistics" data-articleid="(\d+)">.+?<span class="article-type type-\d float-none">\w+</span>
(.+?)
</a>
</h4>
<p class="content">
(.+?)
</p>
<div class="info-box d-flex align-content-center">
<p>
<span class="date">(.+?)</span>
<span class="read-num"><img src="https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png" alt="">(\d+?)</span>(?:
<span class="read-num"><img src="https://csdnimg.cn/release/blogv2/dist/pc/img/commentCountWhite.png" alt="">(\d+?)</span>
</p>
</div>
</div>')*'''
pattern = compile(pattern, DOTALL)
def get_blog_ids_all(pattern, doc_html):
return compile(pattern, DOTALL).findall(doc_html)
#doc_html = open(f"{path}123.html").read()
#datas = get_blog_ids_all(doc_html)
#print(datas)
#exit()
# Modules #
def get(url: str) -> str:
''' 读取url指向的页面源文本 '''
try:
with request.urlopen(url) as response:
return response.read().decode('utf-8') # 以utf-8编码方式返回读取的页面源码文本
except error.HTTPError as e:
raise Exception(f"HTTPError: The server couldn't fulfill the request. Error code: {e.code}")
except error.URLError as e:
raise Exception(f"URLError: Failed to reach a server. Reason: {e.reason}")
except Exception as e:
raise Exception(f"An unexpected error occurred: {e}")
def get_datas(pattern, doc_html):
''' 解析整页单一数据 '''
pattern = compile(pattern, DOTALL)
return pattern.findall(doc_html)
def get_blog_ids(doc_html) -> list:
''' re提取页面blog_ids '''
# ids #
pattern = r'data-articleid="(\d+)"'
blog_ids = get_datas(pattern, doc_html) # 笔记id提取
# titles #
pattern = r' <span class="article-type type-\d float-none">\w+</span>[\n\s]*(.+?)[\n\s]*</a>[\n\s]*</h4>'
titles = get_datas(pattern, doc_html) # 标题提取
# contents #
pattern = r'<p class="content">\s*(.+?)\s*</p>'
contents = [content.split('。')[0] for content in get_datas(pattern, doc_html)] # 提取并截取摘要首句
# date, readed, comment #
pattern = r'(?:<span class="date">(.+?)</span>)[\n\s]*(?:<span class="read-num"><[\w\s="/:.]+>(\d+)</span>)[\n\s]*(?:<span class="read-num"><[\w\s="/:.]+>(\d+)</span>)*'
line = get_datas(pattern, doc_html) # 打包提取发布时间、阅读量、评论数
line = [[item[0], int(item[1]), int(item[-1]) if item[-1].isdigit() else ''] for item in line] # 数值转int
datas =list(zip(blog_ids, titles, contents, line)) # 融合提取数据
return datas
def writer(separator, blog_ids):
''' data写入磁盘文件 '''
filename = f"{path}csdn_blog_ids.csv"
with open(filename, 'w', newline='') as f:
header = 'Id', 'Title', 'Summary','Date', 'Readed' , 'Comment'
f.write(separator.join(header)) # 写字段
for blog_id in blog_ids:
f.write(f"\n{separator.join(map(str, blog_id))}") # 写数据行
# main #
page = 1
blog_ids = [] # blog_ids列表初值
while True:
url = f"{url_base}list/{page}"
try:
doc_html = get(url)
except Exception as e: # 捕获异常提示信息字符串
print(
f"\n{' Url错误或者页面异常 ':-^35}"
f"\nUrl:{url}"
f"\n解释器提示:{e}"
)
#with open(f"{path}local.html", 'w') as f:
#f.write(doc_html) # 当面网页写入磁盘文件,方便异常分析处理(非必须操作)
page_ids = pattern.findall(doc_html) # 抓取整页列表blog_ids
#page_ids = get_blog_ids_all(pattern, doc_html)
print(f"{f' Page: {page:0>2}, Ids: {len(page_ids)} ':-^42}", end='\r')
if not page_ids:
break # 没有匹配到数据,退出数据提取循环
else:
blog_ids += page_ids # 追加page_ids
page += 1 # 更新列表页面
print(f"{f'':^42}", end='\r') # 清屏提示行
print(
f"\n\n{f' {usrname}的blog_ids ':=^41}"
f"\n\n\n{f'共计:{len(blog_ids)}':^39}"
)
# Writer,数据写入磁盘文件 #
try:
writer(r'\\', blog_ids) # 数据写入磁盘
print(f"\n\n{' Data已写入磁盘 ':-^37}")
except Exception as e:
print(
f"\n\n{' 一个错误 ':=^38}"
f"\n异常提示:{e}"
)
print(f"\n\n{f' 程序用时:{time()-START:.2f} 秒 ':=^36}\n\n")
2、运行效果
-
程序运行效果截屏图片
-
csv文本内容
========= qq_35190492的blog_ids ==========
-------------- 共计:194篇 ---------------
阅读总量:713.00w,总计评论:9835
----------- 平均阅读量:36.75k -----------
以下为csv数据——
Id\Title\Summary\Date\Readed\Comment
103847147\毕业5年,我问遍了身边的大佬,总结了他们的学习方法\我问了身边10个大佬,总结了他们的学习方法,原来成功都是有迹可循的\2020-02-13 10:00:26\398121\259
103657160\程序员请照顾好自己,周末病魔差点一套带走我\程序员在一个周末的时间,得了重病,差点当场去世,还好及时挽救回来了\2020-03-13 18:06:22\209811\258
(后续数据行略)
…
2、代码导读
本脚本是一个用于抓取和整理CSDN博客文章信息的Python脚本。
以下是代码的主要功能和结构概述:
2.1 导入模块
脚本开始处导入了必要的Python模块,包括urllib
用于网络请求,re
用于正则表达式处理,以及time
用于计算脚本执行时间。
from urllib import request, error
from re import compile as re_compile, DOTALL, split as re_split
from time import time
2.2 基础变量设置
脚本定义了一些基础变量,包括起始时间、存储路径、用户名以及基于用户名的博客URL。
START = time()
path = '/sdcard/Documents/csdn/temp/'
usrname = 'qq_35190492' # CSDN用户名
url_base = f"https://blog.csdn.net/{usrname}/article/" if usrname[4:].isdigit() else f"https://{usrname}.blog.csdn.net/article/"
2.3 功能模块定义
get(url: str) -> str
该函数用于发送HTTP请求并获取指定URL的页面源码。- 使用了
User-Agent
头部来模拟浏览器请求。 - 通过
try-except
结构处理了可能出现的网络错误。
- 使用了
get_blog_ids(doc_html: str) -> list
该函数使用正则表达式从页面源码中提取博客文章的ID、标题、摘要、日期、阅读量和评论数。- 定义了一个正则表达式模式
pattern
来匹配所需的数据。 - 使用
re.compile
编译正则表达式,并使用findall
方法提取所有匹配的数据。
- 定义了一个正则表达式模式
data_clear(data: list) -> list
该函数用于清洗和整理提取到的数据。- 将标题和摘要截取为第一句。
- 将阅读量和评论数转换为整数。
- 按阅读量对数据进行排序。
writer(separator: str, blog_ids: list, count: str) -> None
该函数将清洗后的数据写入CSV文件。- 定义了文件名和写入模式。
- 写入了标题行和数据行。
organize_data(blog_ids: list) -> None:
该函数用于数据的最终整理和输出。- 调用
data_clear
函数清洗数据。 - 计算总阅读量和评论数。
- 调用
writer
函数将数据写入文件。
- 调用
2.4 主程序逻辑
- 初始化
page
和blog_ids
变量。 - 使用
while
循环遍历博客文章列表页面,直到没有更多数据。 - 在循环中,使用
get
函数获取页面源码,然后使用get_blog_ids
提取数据。 - 如果提取到数据,则调用
organize_data
函数进行整理。
2.5 结束和输出
脚本最后输出程序执行的总时间。
print(f"\n\n{f' 程序用时:{time()-START:.2f} 秒 ':=^36}\n\n")
2.6 注意事项
- 脚本中的路径和用户名需要根据实际情况进行修改。
- 脚本可能需要处理CSDN的反爬虫机制。
- 脚本在运行时可能会受到网络状况和CSDN服务器响应的影响。
3、完整源码(Python)
(源码较长,点此跳过源码)
#!/usr/bin/env python3 # 本脚本代码基于python 3.x 撰写,请阅读和run时注意
print() # 打印空行
print(f"{f' 程序正在加载工具…… ':-^34}", end='\r')
from urllib import request
from urllib import error
from re import compile as re_compile
from re import DOTALL
from re import split as re_split
from time import time
# Base Var #
START = time()
path = '/sdcard/Documents/csdn/temp/'
usrname = 'm0_57158496' # 可以接受csdn注册id个人主页定制域名字符串,如'kunzhi'(昆志说),'qq_44907926'(孤寒者)
usrname = 'qq_35190492' # 敖丙
url_base = f"https://blog.csdn.net/{usrname}/article/" if usrname[4:].isdigit() else f"https://{usrname}.blog.csdn.net/article/" # 分别处理自定义主页地址和默认地址的用户名
# Modules #
def get(url: str) -> str:
''' 读取url指向的页面源文本 '''
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
} # urllib.request.urlopen(url)一般可以缺省请求头,它会给默认一个请求头
req = request.Request(url, headers=headers) # 拼接请求头
try:
with request.urlopen(req) as response:
return response.read().decode('utf-8') # 以utf-8编码方式返回读取的页面源码文本
except error.HTTPError as e:
raise Exception(f"HTTPError: The server couldn't fulfill the request. Error code: {e.code}")
except error.URLError as e:
raise Exception(f"URLError: Failed to reach a server. Reason: {e.reason}")
except Exception as e:
raise Exception(f"An unexpected error occurred: {e}")
def get_blog_ids(doc_html: str) -> list:
''' re提取页面blog_ids '''
pattern = (
r'''<div class="article-item-box csdn-tracking-statistics" data-articleid="(\d+)">'''
r'''.+?<span class="article-.+?</span>\s+(.+?)\s+</a>'''
r'''.+?<p class="content">\s+(.+?)\s+</p>'''
r'''.+?<span class="date">(.+?)</span>'''
r'''.+?<span class="read-num">.+?/readCount.+?>(\d+)</span>'''
r'''\s+(?:<span class="read-num">.+?/commentCount.+?>(\d+)</span>)*'''
) # 简明版,程序用时:0.008107 秒(一页文章列表本地文件,表态解析)
pattern = re_compile(pattern, DOTALL) # 由于python的优化机制,同一pattern总是被仅编译一次,可以不担心重复编译
return pattern.findall(doc_html) # 返回提取数据
def data_clear(data: list) -> list:
''' 清洗数据 '''
for k,blog_id in enumerate(data):
blog_id = list(blog_id) # to list
blog_id[1] = re_split(r'[。.??!!…...]', blog_id[1])[0] # 截取标题第一句文本
blog_id[2] = re_split(r'[。.??!!…...]', blog_id[2])[0] # 截取摘要第一句文本
blog_id[-2] = int(blog_id[-2]) # 阅读量to int
blog_id[-1] = int(blog_id[-1]) if blog_id[-1] else 0 # 修复无评论数据
data[k] = tuple(blog_id) # to tuple
data.sort(key=lambda x: x[-2], reverse=True) # 接阅读量排逆序
return data
def writer(separator: str, blog_ids: list, count: str) -> None:
''' data写入磁盘文件 '''
filename = f"{path}csdn_blog_ids.csv"
with open(filename, 'w', newline='') as f:
f.write(count)
f.write(f"\n\n以下为csv数据——\n")
header = 'Id', 'Title', 'Summary','Date', 'Readed' , 'Comment'
f.write(separator.join(header)) # 写字段
for blog_id in blog_ids:
f.write(f"\n{separator.join(map(str, blog_id))}") # 写数据行
def organize_data(blog_ids: list) -> None:
''' 数据整理 '''
print(f"{f'':^42}", end='\r') # 清屏提示行
blog_ids = data_clear(blog_ids) # 清洗数据
readeds = sum([blog_id[-2] for blog_id in blog_ids])
comments = sum([blog_id[-1] for blog_id in blog_ids])
print(count := (
f"\n\n{f' {usrname}的blog_ids ':=^41}"
f"\n\n\n{f' 共计:{len(blog_ids)}篇 ':-^38}"
f"\n\n{f'阅读总量:{readeds/10000:.2f}w,总计评论:{comments}':^32}"
f"\n\n\n{f' 平均阅读量:{readeds/len(blog_ids)/1000:.2f}k ':-^36}"
))
# Writer,数据写入磁盘文件 #
try:
writer(r'\\', blog_ids, count) # 数据写入磁盘
print(f"\n\n{' Data已写入磁盘 ':-^37}")
except Exception as e:
print(
f"\n\n{' 一个错误 ':=^38}"
f"\n异常提示:{e}"
)
# main #
page = 1
blog_ids = [] # blog_ids列表初值
while True:
url = f"{url_base}list/{page}"
try:
doc_html = get(url)
except Exception as e: # 捕获异常提示信息字符串
print(
f"\n{' Url错误或者页面异常 ':-^35}"
f"\nUrl:{url}"
f"\n解释器提示:{e}"
)
page_ids = get_blog_ids(doc_html) # 提示单页文章列表数据(最多含40条数据)
print(f"{f' Page: {page:0>2}, Ids: {len(page_ids)} ':-^42}", end='\r')
if not page_ids:
break # 没有匹配到数据,退出数据提取循环
else:
blog_ids += page_ids # 追加page_ids
page += 1 # 更新列表页码
if blog_ids: # 有提取到数据,整理数据
organize_data(blog_ids) # 数据整理
else:
print(
f"\n\n{' 没有收集到数据 ':-^35}"
f"\n{'(请查找原因)':^38}"
)
print(f"\n\n{f' 程序用时:{time()-START:.2f} 秒 ':=^36}\n\n")
上一篇: 我的2024(非常年终总结)(年年总年年结年年刻板与雷同,今年松今年垮今年义在字外意不言中)
下一篇:
我的HOT博:
本次共计收集404篇博文笔记信息,总阅读量61.76w。数据采集于2024年11月25日 08:23:38,用时7分56.4秒。阅读量不小于6.00k的有
9
9
9篇。
- 让QQ群昵称色变的神奇代码
地址:https://blog.csdn.net/m0_57158496/article/details/122566500
浏览阅读:6.2w
点赞:25 收藏:89 评论:17
(本篇笔记于2022-01-18 19:15:08首次发布,最后修改于2022-01-20 07:56:47)
- Python列表(list)反序(降序)的7种实现方式
地址:https://blog.csdn.net/m0_57158496/article/details/128271700
浏览阅读:1.3w
点赞:9 收藏:40 评论:8
(本篇笔记于2022-12-11 23:54:15首次发布,最后修改于2023-03-20 18:13:55)
- pandas 数据类型之 DataFrame
地址:https://blog.csdn.net/m0_57158496/article/details/124525814
浏览阅读:1.0w
点赞:7 收藏:40
(本篇笔记于2022-05-01 13:20:17首次发布,最后修改于2022-05-08 08:46:13)
- 个人信息提取(字符串)
地址:https://blog.csdn.net/m0_57158496/article/details/124244618
浏览阅读:1.0w
点赞:3 收藏:20
(本篇笔记于2022-04-18 11:07:12首次发布,最后修改于2022-04-20 13:17:54)
- 罗马数字转换器|罗马数字生成器
地址:https://blog.csdn.net/m0_57158496/article/details/122592047
浏览阅读:8.2k
收藏:3
(本篇笔记于2022-01-19 23:26:42首次发布,最后修改于2022-01-21 18:37:46)
- 统计字符串字符出现的次数
地址:https://blog.csdn.net/m0_57158496/article/details/130517025
浏览阅读:8.1k
点赞:5 收藏:24
(本篇笔记于2023-05-06 22:28:18首次发布,最后修改于2023-05-12 06:21:40)
- Python字符串居中显示
地址:https://blog.csdn.net/m0_57158496/article/details/122163023
浏览阅读:8.0k
点赞:1 收藏:12 评论:1
- 回车符、换行符和回车换行符
地址:https://blog.csdn.net/m0_57158496/article/details/123109488
浏览阅读:6.7k
点赞:2 收藏:4
(本篇笔记于2022-02-24 13:10:02首次发布,最后修改于2022-02-25 20:07:40)
- python清屏
地址:https://blog.csdn.net/m0_57158496/article/details/120762101
浏览阅读:6.1k
点赞:1 收藏:10
截屏图片
(此文涉及ChatPT,曾被csdn多次下架,前几日又因新发笔记被误杀而落马。躺“未过审”还不如回收站,回收站还不如永久不见。😪值此年底清扫,果断移除。留此截图,以识“曾经”。2023-12-31)
精品文章:
- 好文力荐:齐伟书稿 《python 完全自学教程》 Free连载(已完稿并集结成书,还有PDF版本百度网盘永久分享,点击跳转免费🆓下载。)
- OPP三大特性:封装中的property
- 通过内置对象理解python'
- 正则表达式
- python中“*”的作用
- Python 完全自学手册
- 海象运算符
- Python中的 `!=`与`is not`不同
- 学习编程的正确方法
来源:老齐教室
◆ Python 入门指南【Python 3.6.3】
好文力荐:
- 全栈领域优质创作者——[寒佬](还是国内某高校学生)博文“非技术文—关于英语和如何正确的提问”,“英语”和“会提问”是编程学习的两大利器。
- 【8大编程语言的适用领域】先别着急选语言学编程,先看它们能干嘛
- 靠谱程序员的好习惯
- 大佬帅地的优质好文“函数功能、结束条件、函数等价式”三大要素让您认清递归
CSDN实用技巧博文:
- 8个好用到爆的Python实用技巧
- python忽略警告
- Python代码编写规范
- Python的docstring规范(说明文档的规范写法)