• [Python] 命令行模式阅读博客园的博文


    通过Python脚本读取博客园分页数据,把标题、摘要和链接过滤出来,方便我们在命令行中阅读。

    阅读本文可以熟悉一般爬虫的原理,以及指令交互界面的开发。

     

    一、说明

      运行环境:win10/Python 3.5(Win10的玩家可以下载 Window Terminal Preview玩玩,确实不错!);

      主要模块:requests(发送http请求)、lxml.etree(格式化DOM树,xpath查找)、sys(获取命令行参数、重写标准输出等)、os(系统相关、如清屏操作);

      注意:由于时间仓促,没有详细测试,遇到问题麻烦这里反馈;所有英文指令不区分大小写

      后续:后续还会增加查看详情,跳转浏览器等。

      本文地址:https://www.cnblogs.com/reader/p/11487398.html

    二、交互页面

      2、1 开始

        

        直接运行脚本,即可出现如图操作界面。可以输入 1、2和Q进行操作。

      2、2 开始阅读

        

        如上图所示,输入 1 进入的开始阅读界面。可以在头部看到页码。这里操作相对多,N(next)下一页,B(Back)上一页,H(Home)首页,Q(Quit)退出,D {num}(Detail, 后面需要输入标题前面对应的数字进行读取摘要和链接等)。

        

      2、3 阅读摘要和链接 

       如图所示,每行分别对应 标题、链接和摘要。 

    三、代码分析

      3、1 思路

        采集页面-->解析页面内容-->收集必要信息

        

      3.2 数据采集

        如下代码所示,根据页码进行数据采集。这里需要注意摘要的获取方式:

    li.xpath('p')[0].xpath('string(.)')
     1     def download(self, page):
     2         """下载html页面内容"""
     3         self.set_target_url(page)
     4         response = requests.get(self.target_url, headers=self.headers)
     5         if response.status_code == 200:
     6             return response.content
     7         else:
     8             print("download fail")
     9             return ""
    10 
    11     def parse(self, content):
    12         """解析HTML内容"""
    13         html = etree.HTML(content)
    14         lists = html.xpath('//div[@id="post_list"]//div[@class="post_item_body"]')
    15 
    16         del html
    17         k = 1
    18         print('+', '--' * 50, '+')
    19         print('|', str("当前页码:"+str(self.page)).ljust(95), '|')
    20         print('+', '--' * 50, '+')
    21         for li in lists:
    22             title = str(li.xpath('h3/a/text()')[0])
    23             link = li.xpath('h3/a/@href')[0]
    24             desc = li.xpath('p')[0].xpath('string(.)')
    25 
    26             self.lists[k] = {
    27                 'title': title,
    28                 'desc': desc.strip(),
    29                 'link': link
    30             }
    31 
    32             print('|', k, self.formatByWidth(title, 100-1-len(str(k))), '|')
    33             k += 1
    34         del lists
    35         print('+', '--' * 50, '+')

        

    四、源码

      注意:代码仅供学习,杜绝其他方式使用!请注明转发地址。

      1 # -*- coding:UTF-8 -*-
      2 import requests
      3 from lxml import etree
      4 import sys
      5 import io
      6 import os
      7 
      8 
      9 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='gb18030')
     10 
     11 
     12 class CnBlogs:
     13     """"
     14         Auth:reader
     15         发表地址:https://www.cnblogs.com/reader/p/11487398.html
     16         作者地址:https://www.cnblogs.com/reader
     17     """
     18     def __init__(self):
     19         self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'}
     20 
     21         self.target_domain = "https://www.cnblogs.com"
     22         self.page = 1
     23         self.lists = {}
     24 
     25     def clearscreen(self):
     26         """根据系统,清屏操作"""
     27         # window下的清屏方式
     28         os.system("cls")
     29 
     30     def set_target_url(self, page):
     31         if page == 1:
     32             self.target_url = self.target_domain
     33         else:
     34             self.target_url = 'https://www.cnblogs.com/sitehome/p/'+str(page)
     35 
     36     def download(self, page):
     37         """下载html页面内容"""
     38         self.set_target_url(page)
     39         response = requests.get(self.target_url, headers=self.headers)
     40         if response.status_code == 200:
     41             return response.content
     42         else:
     43             print("download fail")
     44             return ""
     45 
     46     def isascii(self, ch):
     47         return ch <= u'u007f'
     48 
     49     def formatByWidth(self, text, width):
     50         """格式化字符串长度"""
     51         count = 0
     52         for u in text:
     53             if not self.isascii(u):
     54                 count += 1
     55         return text + " " * (width - count - len(text))
     56 
     57     def parse(self, content):
     58         """解析HTML内容"""
     59         html = etree.HTML(content)
     60         lists = html.xpath('//div[@id="post_list"]//div[@class="post_item_body"]')
     61 
     62         del html
     63         k = 1
     64         print('+', '--' * 50, '+')
     65         print('|', str("当前页码:"+str(self.page)).ljust(95), '|')
     66         print('+', '--' * 50, '+')
     67         for li in lists:
     68             title = str(li.xpath('h3/a/text()')[0])
     69             link = li.xpath('h3/a/@href')[0]
     70             desc = li.xpath('p')[0].xpath('string(.)')
     71 
     72             self.lists[k] = {
     73                 'title': title,
     74                 'desc': desc.strip(),
     75                 'link': link
     76             }
     77 
     78             print('|', k, self.formatByWidth(title, 100-1-len(str(k))), '|')
     79             k += 1
     80         del lists
     81         print('+', '--' * 50, '+')
     82 
     83     def descopt(self, k):
     84         """读取详情"""
     85         k = int(k)
     86         if k not in self.lists.keys():
     87             return
     88         self.clearscreen()
     89         print('+', '--' * 50, '+')
     90         print('|', self.formatByWidth(self.lists[k]['title'], 100), '|')
     91         print('+', '--' * 50, '+')
     92         print('|', self.formatByWidth(self.lists[k]['link'], 100), '|')
     93         print('+', '--' * 50, '+')
     94 
     95         print('|', self.formatByWidth(self.lists[k]['desc'], 100), '|')
     96 
     97         print('+', '--' * 50, '+')
     98         input("输入任意键返回...
    ")
     99 
    100     def readopt(self):
    101         """开始阅读操作"""
    102         while True:
    103             self.clearscreen()
    104             print("
    ")
    105             html = self.download(page=self.page)
    106             self.parse(html)
    107 
    108             print("[N]:下一页,[B]:上一页,[H]:首页,[D {num}]:简述, [Q]:返回")
    109 
    110             cmd = input("请输入操作编号[N、B、H、D、Q]:")
    111 
    112             if cmd == 'Q' or cmd == 'q':    # 返回
    113                 break
    114             elif cmd == 'N' or cmd == 'n':  # 下一页
    115                 self.page += 1
    116             elif cmd == 'B' or cmd == 'b':  # 上一页
    117                 self.page -= 1
    118                 if self.page <= 0:
    119                     self.page = 1
    120             elif cmd == 'H' or cmd == 'h':  # 首页
    121                 self.page = 1
    122             else:
    123                 cmd = cmd.split(' ')
    124 
    125                 if len(cmd) != 2:
    126                     continue
    127                 # 读取简述
    128                 if cmd[0] == 'D' or cmd[0] == 'd':
    129                     self.descopt(cmd[1])
    130 
    131     def aboutopt(self):
    132         self.clearscreen()
    133         print("博客园地址: https://www.cnblogs.com/reader
    ")
    134         input("输入任意键返回...
    ")
    135 
    136     def start(self):
    137         self.clearscreen()
    138         while True:
    139             print('+', '--'*50, '+')
    140             print('|', "欢迎使用博客园阅读器(reader 开发)".center(88), '|')
    141             print('+', '--' * 50, '+')
    142             print('|', "[1]:开始阅读".center(95), '|')
    143             print('|', "[2]:关于作者".center(95), '|')
    144             print('|', "[Q]:退出软件".center(95), '|')
    145             print('+', '--' * 50, '+')
    146 
    147             cmd = input("请输入操作编号[1、2、Q]:")
    148             if cmd == '1':
    149                 self.readopt()
    150             elif cmd == '2':
    151                 self.aboutopt()
    152             elif cmd == 'Q' or cmd == 'q':
    153                 break
    154 
    155             os.system("cls")
    156 
    157         print("已退出,欢迎使用!")
    158 
    159 
    160 if __name__ == "__main__":
    161     obj = CnBlogs()
    162     obj.start()
    View Code
  • 相关阅读:
    Tomcat配置JNDI
    (转)通过反编译深入理解Java String及intern
    (转)Java8内存模型-永久代(PermGen)和元空间(Metaspace)
    排序算法
    并发编程
    MySQL
    Go语言
    Go语言
    Go语言
    Go语言
  • 原文地址:https://www.cnblogs.com/reader/p/11487398.html
Copyright © 2020-2023  润新知