跳转至

Python抓取博客记录,获取标题与url

更新日期 2021-10-13
  • 2021-10-13 创建文档

在博客网站发布了一些博客。总共有四十多篇。现在查看这些博客需要翻页,不是很方便。 想要弄出一个列表,把标题和链接展示出来。如果手动去复制粘贴,耗时耗力,也不够自动化。 有没有什么自动化的方法呢?想到以前用python做过抓取的功能。

开发环境:

  • Python3.7
  • PyCharm 2018.3.7 (Community Edition)
  • macOS 11.4

安装scrapy

我们主要使用的框架是scrapy,官网 https://scrapy.org/

如果需要换用清华的pip源,执行下面的命令

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pip -U
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

根据官网文档进行安装

pip3 install Scrapy

分析目标网页

目标网页的部分html如下

<div class="blog-menu blog-menu-noImg">
    <div class="blog-menu-header blog_no_attachment">
        <a id="portal_usercenter_2_usernew_blog_title_cus_i_0" href="/blogs/301790" class="common-blog-title" title="Kotlin协程取消与超时" target="_blank" style="margin-left: 0px; color: rgb(51, 51, 51);"><span class="blog-title-wrap" style="overflow-wrap: break-word;">
            Kotlin协程取消与超时
        </span></a></div>
需要提取的是标题(title)和网址(url)。

shell工具

使用scrapy shell工具来分析一下目标网页

scrapy shell 'https://bbs.huaweicloud.com/community/usersnew/id_1606985929124732/page_1'
windows下的url需要用双引号

可以看到如下的运行结果

2021-10-13 09:46:47 [asyncio] DEBUG: Using selector: KqueueSelector
[s] Available Scrapy objects:
[s]   scrapy     scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s]   crawler    <scrapy.crawler.Crawler object at 0x7fd889766990>
[s]   item       {}
[s]   request    <GET https://bbs.huaweicloud.com/community/usersnew/id_1606985929124732/page_1>
[s]   response   <200 https://bbs.huaweicloud.com/community/usersnew/id_1606985929124732/page_1>
[s]   settings   <scrapy.settings.Settings object at 0x7fd88987bb50>
[s]   spider     <DefaultSpider 'default' at 0x7fd889c7b710>
[s] Useful shortcuts:
[s]   fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s]   fetch(req)                  Fetch a scrapy.Request and update local objects 
[s]   shelp()           Shell help (print this help)
[s]   view(response)    View response in a browser
2021-10-13 09:46:48 [asyncio] DEBUG: Using selector: KqueueSelector

尝试用scrapy的css()方法来提取元素,操作它的response变量

例如提取div.blog-menu

In [2]: response.css('div.blog-menu')
Out[2]: 
[<Selector xpath="descendant-or-self::div[@class and contains(concat(' ', normalize-space(@class), ' '), ' blog-menu ')]" data='<div class="blog-menu blog-menu-noImg"><'>,
...
可以得到页面上所有满足要求的元素。拿到的元素是Selector,可以再进行下一步的操作。

用for循环读取提取到的元素,在此基础上,去抓取中文标题

In [6]: for item in response.css('div.blog-menu'):
   ...:     print(item.css('a.common-blog-title::attr(title)').extract()[0])
   ...: 
Kotlin协程取消与超时 - AnRFDev
Android Kotlin协程入门 - AnRFDev
Kotlin协程基础 - AnRFDev
Kotlin协程入门 - AnRFDev
Android View post 方法 - AnRFDev
Android Activity 传递Parcelable对象 - AnRFDev
Android Handler,Looper与MessageQueue使用与分析 - AnRFDev
Android线程池使用介绍 - AnRFDev
Java线程介绍 - AnRFDev
使用ECharts绘制网址径向树状图 - AnRFDev

a.common-blog-title::attr(title)表示的是我们要查找<a>里面的内容,指定class为common-blog-title,并且查找title属性。 css().extract()将结果列表提取出来。最后得到我们关心的信息。

获取url同理,把提取部分修改为::attr(href)

代码

前面用shell工具进行分析,我们了解提取目标信息的方法。接下来写Python代码。

在合适的地方新建一个scrapy工程

scrapy startproject blog
可以得到一系列文件
blog
    spiders
        .gitignore
        __init__.py
    __init__.py
    items.py
    middlewares.py
    pipelines.py
    settings.py

spiders目录里新建一个文件Hw.py,它就是我们的“蜘蛛”。完整代码如下。

import json

import scrapy


def cmp(item):
    return item['page']


class HwBlog(scrapy.Spider):
    """
    在最外层的blog目录进行操作
    scrapy crawl hw
    """
    name = "hw"  # scrapy crawl hw
    res_list = []
    req_count = 0
    total_url = 5

    def start_requests(self):
        self.res_list = []
        urls = []
        base_url = 'https://bbs.huaweicloud.com/community/usersnew/id_1606985929124732/page_'
        for i in range(1, self.total_url + 1):
            urls.append(base_url + str(i))

        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        self.req_count = self.req_count + 1
        page = response.url.split("_")[-1]

        for item in response.css('div.blog-menu'):
            title_se = item.css("a.common-blog-title")
            blog_url = 'https://bbs.huaweicloud.com' + (title_se.css("::attr(href)").extract()[0])
            blog_title = title_se.css("::attr(title)").extract()[0]
            self.res_list.append({"title": blog_title, "url": blog_url, "page": page})

        json_res = json.dumps(self.res_list, ensure_ascii=False)
        print(json_res)

        res_file_path = 'raw/hw.json'
        with open(res_file_path, 'w+') as f:
            f.write(json_res)

        if self.req_count < self.total_url:
            return
        res_md = 'raw/hw.md'
        self.res_list.sort(key=cmp)  # 用页码来排序
        with open(res_md, 'w+') as f:
            f.writelines('## 华为云社区')
            f.write('\n博客数量:' + str(len(self.res_list)) + '\n')
            for d in self.res_list:
                f.write('\n')
                f.write('- [' + d['title'] + '](' + d['url'] + ')')

要启动的话,输入以下命令

scrapy crawl hw

接下来简单看一下代码

变量

name是蜘蛛的名字。我们启动的时候会用到它。这个名字由我们自己定义。

res_list是暂存结果的列表。把获取到的结果暂时存放在里面。

total_url表示一共要爬几个页面

req_count表示请求次数

start_requests(self)

在这个方法里进行一些配置工作。比如配置目标url。 我们是预先知道有5个页面,所以配置了5个url。

scrapy.Request(url=url, callback=self.parse)构建请求

parse是回调函数,请求成功后走这个方法。

parse(self, response)

请求成功后,结果保存在response中。前面用shell进行的操作,可以直接写成python代码。

当请求次数达到目标后,开始写文件。

小结

这是Python scrapy的一次简单应用。

安装scrapy,分析目标网页。把获取到的数据整理后写成markdown文件。

讲解视频

开发闲谈 - bilibili

本站说明

一起在知识的海洋里呛水吧。广告内容与本站无关。如果喜欢本站内容,欢迎投喂作者,谢谢支持服务器。

AndroidTutorial AndroidTutorial 反馈问题 讨论区 最近更新 投喂作者

Ads