本地手集博客id“升级”在线抓取——简陋版——(2024年终总结1.1)

我之前每每发布笔记都用csv纯文本记录,一个机缘巧得文章列表api实现在线整理自已的文章阅读量数据。


(笔记模板由python脚本于2025年01月10日 18:48:25创建,本篇笔记适合喜欢钻牛角尖的coder翻阅)


【学习的细节是欢悦的历程】



  自学并不是什么神秘的东西,一个人一辈子自学的时间总是比在学校学习的时间长,没有老师的时候总是比有老师的时候多。
            —— 华罗庚


---== 彰显C位 ==---

  1. ,可以在评论区书写任何想法
  2. (我将在看到的第一时间回应)
  3. 点击这里回转《我的2024》

---== 彰显C位 ==---

等风来,不如追风去……

我的 2 0 2 4  我的 2 0 2 4  我的 2 0 2 4


每每发布笔记都用csv记录
手写id到在线捕获
(一个机缘巧得文章列表api实现在线)


我的 2 0 2 4  我的 2 0 2 4  我的 2 0 2 4


本文质量分:

96 96 96

本文地址: https://blog.youkuaiyun.com/m0_57158496/article/details/145063820

优快云质量分查询入口:http://www.youkuaiyun.com/qc


目 录

  • ◆ 手写id到在线捕获
    • 1、前言
    • 2、运行效果
    • 3、代码导读
      • 3.1 导入模块
      • 3.2 基础变量设置
      • 3.3 功能模块定义
      • 3.4 主程序逻辑
      • 3.5 结束和输出
      • 3.6 注意事项
    • 4、完整源码(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.youkuaiyun.com/{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 0 2 4  我的 2 0 2 4  我的 2 0 2 4


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 0 2 4  我的 2 0 2 4  我的 2 0 2 4


3、代码导读


  本脚本是一个用于抓取和整理优快云博客文章信息的Python脚本。


以下是代码的主要功能和结构概述:

3.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


3.2 基础变量设置


  脚本定义了一些基础变量,包括起始时间、存储路径、用户名以及基于用户名的博客URL。


START = time()
path = '/sdcard/Documents/csdn/temp/'
usrname = 'qq_35190492'  # 优快云用户名
url_base = f"https://blog.youkuaiyun.com/{usrname}/article/" if usrname[4:].isdigit() else f"https://{usrname}.blog.youkuaiyun.com/article/"


3.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函数将数据写入文件。

3.4 主程序逻辑

  • 初始化pageblog_ids变量。
  • 使用while循环遍历博客文章列表页面,直到没有更多数据。
  • 在循环中,使用get函数获取页面源码,然后使用get_blog_ids提取数据。
  • 如果提取到数据,则调用organize_data函数进行整理。

3.5 结束和输出

脚本最后输出程序执行的总时间。

 
print(f"\n\n{f' 程序用时:{time()-START:.2f} 秒 ':=^36}\n\n")
 

3.6 注意事项

  • 脚本中的路径和用户名需要根据实际情况进行修改。
  • 脚本可能需要处理优快云的反爬虫机制。
  • 脚本在运行时可能会受到网络状况和优快云服务器响应的影响。



我的 2 0 2 4  我的 2 0 2 4  我的 2 0 2 4


4、完整源码(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.youkuaiyun.com/{usrname}/article/" if usrname[4:].isdigit() else f"https://{usrname}.blog.youkuaiyun.com/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》



我的 2 0 2 4  我的 2 0 2 4  我的 2 0 2 4


上一篇:  我的2024(非常年终总结)(年年总年年结年年刻板与雷同,今年松今年垮今年义在字外意不言中)
下一篇: 



我的HOT博:

  本次共计收集404篇博文笔记信息,总阅读量61.76w。数据采集于2024年11月25日 08:23:38,用时7分56.4秒。阅读量不小于6.00k的有 9 9 9篇。

  1. 让QQ群昵称色变的神奇代码
    地址:https://blog.youkuaiyun.com/m0_57158496/article/details/122566500
    浏览阅读:6.2w
    点赞:25 收藏:89 评论:17
    (本篇笔记于2022-01-18 19:15:08首次发布,最后修改于2022-01-20 07:56:47)

  2. Python列表(list)反序(降序)的7种实现方式
    地址:https://blog.youkuaiyun.com/m0_57158496/article/details/128271700
    浏览阅读:1.3w
    点赞:9 收藏:40 评论:8
    (本篇笔记于2022-12-11 23:54:15首次发布,最后修改于2023-03-20 18:13:55)

  3. pandas 数据类型之 DataFrame
    地址:https://blog.youkuaiyun.com/m0_57158496/article/details/124525814
    浏览阅读:1.0w
    点赞:7 收藏:40 
    (本篇笔记于2022-05-01 13:20:17首次发布,最后修改于2022-05-08 08:46:13)

  4. 个人信息提取(字符串)
    地址:https://blog.youkuaiyun.com/m0_57158496/article/details/124244618
    浏览阅读:1.0w
    点赞:3 收藏:20 
    (本篇笔记于2022-04-18 11:07:12首次发布,最后修改于2022-04-20 13:17:54)

  5. 罗马数字转换器|罗马数字生成器
    地址:https://blog.youkuaiyun.com/m0_57158496/article/details/122592047
    浏览阅读:8.2k
    收藏:3 
    (本篇笔记于2022-01-19 23:26:42首次发布,最后修改于2022-01-21 18:37:46)

  6. 统计字符串字符出现的次数
    地址:https://blog.youkuaiyun.com/m0_57158496/article/details/130517025
    浏览阅读:8.1k
    点赞:5 收藏:24 
    (本篇笔记于2023-05-06 22:28:18首次发布,最后修改于2023-05-12 06:21:40)

  7. Python字符串居中显示
    地址:https://blog.youkuaiyun.com/m0_57158496/article/details/122163023
    浏览阅读:8.0k
    点赞:1 收藏:12 评论:1
  8. 回车符、换行符和回车换行符
    地址:https://blog.youkuaiyun.com/m0_57158496/article/details/123109488
    浏览阅读:6.7k
    点赞:2 收藏:4 
    (本篇笔记于2022-02-24 13:10:02首次发布,最后修改于2022-02-25 20:07:40)

  9. python清屏
    地址:https://blog.youkuaiyun.com/m0_57158496/article/details/120762101
    浏览阅读:6.1k
    点赞:1 收藏:10 

推荐条件 阅读量突破6.00k
(更多热博,请点击蓝色文字跳转翻阅)

  • 截屏图片
    在这里插入图片描述
      (此文涉及ChatPT,曾被csdn多次下架,前几日又因新发笔记被误杀而落马。躺“未过审”还不如回收站,回收站还不如永久不见。😪值此年底清扫,果断移除。留此截图,以识“曾经”。2023-12-31)



我的 2 0 2 4  我的 2 0 2 4  我的 2 0 2 4


老齐漫画头像

精品文章:

来源:老齐教室


Python 入门指南【Python 3.6.3】


好文力荐:


优快云实用技巧博文:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦幻精灵_cq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值