scrapy爬虫框架实现简单案例:爬取阳光平台内容

scrapy爬虫框架的熟悉

近期在学习scrapy爬虫框架,通过爬取阳光平台的内容来进一步理解并熟悉此框架。为了以后能够快速回顾这个爬虫框架,在此做个记录。

首先,明确爬取目标。

scrapy爬虫框架实现简单案例:爬取阳光平台内容
这个就是待抓取的平台,其中抓取的数据有标题、日期
不仅如此,我们还需要抓取其中的详细内容,我们随机点击一个链接,便知道需要抓取的是详情内容,如下图
scrapy爬虫框架实现简单案例:爬取阳光平台内容
这样,我们就已经明确了目标,那么就开始朝着这个方向继续前进

其次,观察所需爬取平台的特征(即观察是否适合用xpath方式/json方式)

个人一开始比较倾向于xpath方式爬取,毕竟这个方式对我来说比较亲和,于是便开始对比element和network的内容是否能够一一对应。
scrapy爬虫框架实现简单案例:爬取阳光平台内容
scrapy爬虫框架实现简单案例:爬取阳光平台内容
对比以上两个图,发现两栏的内容相似度较高,都有table,并且对应的tr/td内容比较规则,故初步判定可使用xpath方式
scrapy爬虫框架实现简单案例:爬取阳光平台内容
但是,在用xpath方式时要格外注意这个tbody字符串,它在element处存在,但在network中却不存在(如下图)scrapy爬虫框架实现简单案例:爬取阳光平台内容
这一点在编写程序时要格外注意

最后,开始创建scrapy项目并生成爬虫

创建的步骤就不一一赘述了。
创建完后如下图所示:
scrapy爬虫框架实现简单案例:爬取阳光平台内容

下面我们直接开始编写主要程序部分:

先爬取基本的信息
from yangguang.items import YangguangItem

class YgSpider(scrapy.Spider):
    name = 'yg'
    allowed_domains = ['sun0769.com']
    start_urls = ['http://wz.sun0769.com/index.php/question/report?page=']

    def parse(self, response):
        li_list = response.xpath("//div[@class='greyframe']/table[2]//tr")[1:]
        for li in li_list:
            item = YangguangItem()
            item["link"] = li.xpath("./td[2]/a[2]/@href").extract_first()  # 爬取进入详情页面的链接
            item["title"] = li.xpath("./td[2]/a[2]/@title").extract_first()  # 爬取主题
            item["date"] = li.xpath("./td[5]/text()").extract_first()  # 爬取日期
			yield item

解析:
因为是xpath方式,首页url链接可以直接是网址名:
http://wz.sun0769.com/index.php/question/report?page=
xpath节点内容需通过XPath Helper插件尝试无误后敲入代码中(对了,说到这些插件工具,很多人都说对于开发者来说更多推荐使用谷歌浏览器/火狐浏览器,至于为什么我也不太清楚,有大佬可以指点的么?)

class YangguangItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    link = scrapy.Field()
    title = scrapy.Field()
    date = scrapy.Field()
    detail_content = scrapy.Field()

解析:
此处的代码是为呼应前面类的调用

item = YangguangItem()
class YangguangPipeline(object):
    def process_item(self, item, spider):
        print(item)
        return item
LOG_LEVEL = "WARNING"
ITEM_PIPELINES = {
   'yangguang.pipelines.YangguangPipeline': 300,
} 
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'

添加第一项内容可使得输出的内容比较简洁,只有警告程度以上的日志内容才会输出
第二项内容在文件中本身是注释的方式出现,我们把它的注释清除即可
第三项内容:加上模拟浏览器行为所需的用户代理

如此,我们就已初步生成了可用的爬虫,我们运行下看看结果
scrapy爬虫框架实现简单案例:爬取阳光平台内容
爬取的结果中有日期、链接、主题,看来这个初生的爬虫的还是比较健康的。
接下来我们要壮大它

爬取链接中的详情内容

我们前面说过,阳光平台的详情内容才是我们真正需要的,而详情内容是通过链接进一步提取,因此我们需要进一步扩充程序。

  • yg.py 文件:(扩充)
class YgSpider(scrapy.Spider):
    name = 'yg'
    allowed_domains = ['sun0769.com']
    start_urls = ['http://wz.sun0769.com/index.php/question/report?page=']

    def parse(self, response):
        li_list = response.xpath("//div[@class='greyframe']/table[2]//tr")[1:]
        for li in li_list:
            item = YangguangItem()
            item["link"] = li.xpath("./td[2]/a[2]/@href").extract_first()
            item["title"] = li.xpath("./td[2]/a[2]/@title").extract_first()
            item["date"] = li.xpath("./td[5]/text()").extract_first()
            # yield item
            yield scrapy.Request(
                item["link"],
                callback=self.parse_detail,
                meta={"item": item}
            )
    def parse_detail(self, response):  # 详情页面处理
        item = response.meta["item"]
        item["detail_content"] = response.xpath("//div[@class='wzy1']//tr[1]/td[@class='txt16_3']//text()").extract()  # 输出详情投诉内容
        yield item

将前面获取的链接link融入生成器中,并且另外定义一个方法来进行详情页面的处理。
这里主要是增加了提取 detail_content 的一项内容
scrapy爬虫框架实现简单案例:爬取阳光平台内容
我们启动爬虫后发现内容有扩充,增加了detail_content这项内容,只是内容含有其他杂质,此时我们可通过正则表达式来提取我们真正需要的内容。

import re


class YangguangPipeline(object):
    def process_item(self, item, spider):
        item["detail_content"] = self.process_content(item["detail_content"])
        print(item)
        return item

    def process_content(self, content):
        """对详情内容进行(正则)处理"""
        content = [re.sub("\xa0|\s", "", i) for i in content]  # 将指定字符替换为空字符
        content = [i for i in content if len(i) > 0]  # 去除空字符
        return content

再次启动爬虫
scrapy爬虫框架实现简单案例:爬取阳光平台内容
此时我们发现,detail_content这项内容已经变得简洁清晰明了,不再有其他无关的字符串干扰我们的视野。

至此,我们的爬虫已经能够爬取一整页的所需的信息。不过,我们的爬虫还可以进一步成长,能够去猎食更多的信息,而不再满足仅仅一页的猎物。

接下来,我们继续扩充爬虫,来爬取多页的内容。

  • yg.py 文件:(parse方法中扩充)
    def parse(self, response):
        li_list = response.xpath("//div[@class='greyframe']/table[2]//tr")[1:]
        for li in li_list:
            item = YangguangItem()
            item["link"] = li.xpath("./td[2]/a[2]/@href").extract_first()
            item["title"] = li.xpath("./td[2]/a[2]/@title").extract_first()
            item["date"] = li.xpath("./td[5]/text()").extract_first()
            # yield item
            yield scrapy.Request(
                item["link"],
                callback=self.parse_detail,
                meta={"item": item}
            )

        # 处理下一页
        next_url = response.xpath("//a[text()='>']/@href").extract_first()
        print("*" * 50)
        print(next_url)
        if next_url is not None:
            yield scrapy.Request(
                next_url,
                callback=self.parse
            )

最后启动爬虫,效果如下所示
scrapy爬虫框架实现简单案例:爬取阳光平台内容
最终,我们就完成了整个爬虫,只不过这个爬虫并不是太健康,毕竟没有考虑应对所谓反爬虫机制的策略方式,这个爬虫对服务器可能也不是太友好,毕竟会给对方的服务器增加压力。当然,我们的这个小爬虫还不到他人动用爬虫机制的地步,毕竟真的还小。。。

总结:

其实仔细想想,这整个爬虫生成过程很简单,而且描述也只是蜻蜓点水,因为只说了怎么做却没有说为什么这么做,即所谓的知其然,却不知其所以然。
例如下面这个代码,为什么后面要加extract_first()方法

item["link"] = li.xpath("./td[2]/a[2]/@href").extract_first()

再如,下面这个代码的原理机制

            yield scrapy.Request(
                item["link"],
                callback=self.parse_detail,
                meta={"item": item}
            )

后面需要慢慢补充,毕竟要进入内行,必须知其然并知其所以然。


为记录我的学习过程,制作我的第一篇原创博客,还请各位大佬不要嫌弃。