资讯专栏INFORMATION COLUMN

爬虫学习之基于Scrapy的网络爬虫

BingqiChen / 859人阅读

摘要:不过不用担心,中有很多非常优秀的爬虫框架,比如我们接下来要学习到的。结合以上分析我们基本确定了本次爬虫的各个路线入口,接下来我们就开始通过程序来实现本次的目标。这里我们的目的是建立一种写爬虫的思路,而不在于怎么使用工具来爬数据。

概述

在上一篇文章《爬虫学习之一个简单的网络爬虫》中我们对爬虫的概念有了一个初步的认识,并且通过Python的一些第三方库很方便的提取了我们想要的内容,但是通常面对工作当作复杂的需求,如果都按照那样的方式来处理效率非常的低,这通常需要你自己去定义并实现很多非常基础的爬虫框架上的功能,或者需要组合很多Python第三方库来做。不过不用担心,Python中有很多非常优秀的爬虫框架,比如我们接下来要学习到的Scrapy。Scrapy官方有很经典的入门文档说明,这一篇仅仅是通过一个简单的实例来了解Scrapy这个库是如何来进行网络内容提取的,更深入的学习请阅读Scrapy官方文档。

建立目标

同样在做任何事情之前都需要明确目标,那这次我们的目标是爬取一些技术性的文章并存储到数据库中。这就需要有目标网址和数据库结构,数据库我们选择使用MySql,目标网站我们找了一个叫脚本之家的内容站。我们这里首先准备好一张用于存储文章的表结构:

CREATE TABLE `articles` (
  `id` mediumint(8) AUTO_INCREMENT NOT NULL,
  `title` varchar(255) DEFAULT NULL,
  `content` longtext,
  `add_date` int(11) DEFAULT 0,
  `hits` int(11) DEFAULT "0",
  `origin` varchar(500) DEFAULT "",
  `tags` varchar(45) DEFAULT "",
  PRIMARY KEY (`id`),
  KEY `add_date` (`add_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
分析目标结构

这里我们首先需要爬取得入口是“网络编程”这个节点,主入口网址为(http://www.jb51.net/list/index_1.htm) 打开这个网站我们通过Chrome或者其他浏览器的查看元素来分析当前页面的HTML语义结构,如下图所示:

从图中红色框线的部分可以看出,这里是我们需要在“网络编程”这个节点下需要提取的所有文章的主分类入口,通过这些入口可以进去到不同文章分类的列表中。所以根据初步结构分析,我们得出本次爬虫的爬取路线为:

从主入口进去 -> 提取当前入口中的所有分类 -> 通过分类入口进入到分类列表 -> 通过列表进入到文章页

分类入口确定了接下来看看我们的分类列表,随意点开一个分类入口,打开列表如下图所示:

这里我框出了两个主要部分,第一个是文章的标题,第二个是分页,文章对应的URL就是我们接下来需要爬取文章内容的入口,这里需要注意的是分页的处理,通过分页的最后一页我们可以知道当前这类列表共有多少页文章。结合以上分析我们基本确定了本次爬虫的各个路线入口,接下来我们就开始通过程序来实现本次的目标。

实现爬虫

在实现爬虫之前我们通过一张图来对Scrapy有个基本的认识,为了保持本章内容的简洁性,我们这里暂时不会讨论Item Pipeline部分,Scrapy架构图如下所示(图片来自网络):

从图中可以很清晰的看到Scrapy所包含的几大块,下面我们通过代码来演示我们所用到的基础功能部分。
主要依赖第三方库:

web.py web框架,这里只用到了database部分,将来会用来进行内容展示
scrapy 爬虫框架,这里只用到了最基本的内容提取

这里还会用到一些xpath相关知识,请自行Google了解xpath语法

# -*- coding:utf-8 -*-
"""by sudo rm -rf  http://imchenkun.com"""
import scrapy
from scrapy.http import Request
import web
import time

db = web.database(dbn="mysql", host="127.0.0.1", db="imchenkun", user="root", pw="root")

# 允许的站点域
allow_domain = "jb51.net"

base_url = "http://www.jb51.net"

# 列表页
list_url = "http://www.jb51.net/list/list_%d_%d.htm"

# 列表分页
list_page = 1

# 文章页
crawl_url = "http://www.jb51.net/article/%d.htm"


class JB51Spider(scrapy.Spider):
    name = "jb51"
    start_urls = [
        "http://www.jb51.net/list/index_1.htm"
    ]

    cate_list = []

    def parse(self, response):
        cate_id = response.selector.xpath("//div[@class="index_bor clearfix"]/div[@class="index_con"]/span/a/@href").re("(d+)")[::2]
        for id in cate_id:
            cate_url = list_url % (int(id), 1)
            yield Request(cate_url, callback=self.parse_page)

    def parse_page(self, response):
        _params = response.selector.xpath("//div[@class="dxypage clearfix"]/a[last()]/@href").re("(d+)")
        cate_id = int(_params[0]) # 分类编号
        count = int(_params[1]) # 总页数

        article_urls = response.selector.xpath("//div[@class="artlist clearfix"]/dl/dt/a/@href").extract()
        # 处理第一页
        for article_url in article_urls:
            yield Request(base_url + article_url, callback=self.parse_article)

        # 处理其他页
        for page in range(1, count):
            url = (list_url % (cate_id, page + 1))
            yield Request(url, callback=self.parse_list)

    def parse_list(self, response):
        """解析文章列表"""
        article_urls = response.selector.xpath("//div[@class="artlist clearfix"]/dl/dt/a/@href").extract()
        for article_url in article_urls:
            yield Request(base_url + article_url, callback=self.parse_article)

    def parse_article(self, response):
        """解析文章内容"""
        title = response.selector.xpath("//div[@class="title"]/h1/text()").extract()[0]
        content = response.selector.xpath("//div[@id="content"]").extract()[0]
        tags = ",".join(response.selector.xpath("//div[@class="tags mt10"]/a/text()").extract())
        
        results = db.query("select count(0) as total from articles where origin=$origin", vars = { "origin": response.url })
        if results[0].total <= 0:
            db.insert("articles",
                      title=title,
                      origin=response.url,
                      content=content,
                      add_date=int(time.time()),
                      hits=0,
                      tags=tags
            )

安装Scrapy后以上代码通过以下命令执行:

scrapy runspider jb51_spider.py

本次运行后的效果在数据库中可以见如下图所示:

Github地址

总结

本篇文章我们主要了解了基本的Scrapy Spider部分,而且通过对目标网站的结构分析使用xpath进行内容的提取,以及分页的处理。这里我们的目的是建立一种写爬虫的思路,而不在于怎么使用工具来爬数据。首先确定目标,然后分析目标,再借助现有工具进行内容提取,提取内容的过程中会遇到各种问题,这个时候我们再来逐个解决这些问题,直到我们的爬虫能够无障碍的运行。接下来我会使用Scrapy更多的功能将继续探索Item的定义,Pipeline的实现以及如何使用代理。

特别申明:本文所提到的脚本之家网站只是拿来进行爬虫的技术交流学习,读者涉及到的所有侵权问题都与本人无关,也希望大家在学习实战的过程中不要大量的爬取内容对服务器造成负担

本文首发在sudo rm -rf 采用署名(BY)-非商业性使用(NC)-禁止演绎(ND) 转载请注明原作者

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/38058.html

相关文章

  • 爬虫习之基于 Scrapy 爬虫自动登录

    摘要:概述在前面两篇爬虫学习之基于的网络爬虫和爬虫学习之简单的网络爬虫文章中我们通过两个实际的案例,采用不同的方式进行了内容提取。 概述 在前面两篇(爬虫学习之基于Scrapy的网络爬虫和爬虫学习之简单的网络爬虫)文章中我们通过两个实际的案例,采用不同的方式进行了内容提取。我们对网络爬虫有了一个比较初级的认识,只要发起请求获取响应的网页内容,然后对内容进行格式化存储。很多时候我们抓取到的内容...

    Panda 评论0 收藏0
  • 首次公开,整理12年积累博客收藏夹,零距离展示《收藏夹吃灰》系列博客

    摘要:时间永远都过得那么快,一晃从年注册,到现在已经过去了年那些被我藏在收藏夹吃灰的文章,已经太多了,是时候把他们整理一下了。那是因为收藏夹太乱,橡皮擦给设置私密了,不收拾不好看呀。 ...

    Harriet666 评论0 收藏0
  • 零基础如何爬虫技术

    摘要:楚江数据是专业的互联网数据技术服务,现整理出零基础如何学爬虫技术以供学习,。本文来源知乎作者路人甲链接楚江数据提供网站数据采集和爬虫软件定制开发服务,服务范围涵盖社交网络电子商务分类信息学术研究等。 楚江数据是专业的互联网数据技术服务,现整理出零基础如何学爬虫技术以供学习,http://www.chujiangdata.com。 第一:Python爬虫学习系列教程(来源于某博主:htt...

    KunMinX 评论0 收藏0
  • 爬虫习之一个简单网络爬虫

    摘要:概述这是一个网络爬虫学习的技术分享,主要通过一些实际的案例对爬虫的原理进行分析,达到对爬虫有个基本的认识,并且能够根据自己的需要爬到想要的数据。 概述 这是一个网络爬虫学习的技术分享,主要通过一些实际的案例对爬虫的原理进行分析,达到对爬虫有个基本的认识,并且能够根据自己的需要爬到想要的数据。有了数据后可以做数据分析或者通过其他方式重新结构化展示。 什么是网络爬虫 网络爬虫(又被称为网页...

    Anleb 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<