Scrapy框架开发爬虫入门:Spider是什么?

2022-10-1820:06:05云计算与物联网Comments1,112 views字数 6082阅读模式

Spider是什么?

Spider是一个Scrapy提供的基本类,Scrapy中包含的其他基本类(例如CrawlSpider)以及自定义的spider都必须继承这个类。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

Spider是定义如何抓取某个网站的类,包括如何执行抓取以及如何从其网页中提取结构化数据。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

源码如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

所有爬虫的基类,用户定义的爬虫必须从这个类继承
class Spider(object_ref):

    #name是spider最重要的属性,而且是必须的。一般做法是以该网站(domain)(加或不加 后缀 )来命名spider。 例如,如果spider爬取 mywebsite.com ,该spider通常会被命名为 mywebsite
    name = None

    #初始化,提取爬虫名字,start_ruls
    def __init__(self, name=None, **kwargs):
     #判断是否存在爬虫名字name,没有则会报错
        if name is not None:
            self.name = name
        elif not getattr(self, 'name', None):
            raise ValueError("%s must have a name" % type(self).__name__)

        # python对象或类型通过内置成员__dict__来存储成员信息
        self.__dict__.update(kwargs)

        #判断是否存在start_urls列表,从列表中获取到页面的URL开始请求,后续的URL将会从获取到的数据中提取。
        if not hasattr(self, 'start_urls'):
            self.start_urls = []

    # Scrapy执行后的日志信息
    def log(self, message, level=log.DEBUG, **kw):
        log.msg(message, spider=self, level=level, **kw)

    # 判断对象object的属性是否存在,不存在则做断言处理
    def set_crawler(self, crawler):
        assert not hasattr(self, '_crawler'), "Spider already bounded to %s" % crawler
        self._crawler = crawler

    @property
    def crawler(self):
        assert hasattr(self, '_crawler'), "Spider not bounded to any crawler"
        return self._crawler

    @property
    def settings(self):
        return self.crawler.settings

    #该方法将读取start_urls内的地址,并为每一个地址生成一个Request对象,交给Scrapy下载并返回Response
    #注意:该方法仅调用一次
    def start_requests(self):
        for url in self.start_urls:
          # 生成Request对象的函数
            yield self.make_requests_from_url(url)

    #Request对象默认的回调函数为parse(),提交的方式为get
    def make_requests_from_url(self, url):
        return Request(url, dont_filter=True)

    #默认的Request对象回调函数,处理返回的response。
    #生成Item或者Request对象。用户需要自己重写该方法中的内容
    def parse(self, response):
        raise NotImplementedError

    @classmethod
    def handles_request(cls, request):
        return url_is_from_spider(request.url, cls)

    def __str__(self):
        return "<%s %r at 0x%0x>" % (type(self).__name__, self.name, id(self))

    __repr__ = __str__

因此可以总结出Scrapy爬取数据的过程如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

1. Spider的入口方法(start_requests())请求start_urls列表中定义的url,返回Request对象(同时默认传给它一个名为parse的回调函数)。2. 下载器获取Respose后,回调函数会解析Reponse,返回(yield)的结果可能是字典、Item或是Request对象,亦或是这些对象组成的可迭代类型。其中,返回的Request也会包含一个回调函数,并在被下载之后被回调函数处理(即重复第2步)。3. 解析数据可以使用Scrapy自带的Selectors工具或者lxml、BeautifulSoup等模块。4. 最后Scrapy将返回的数据字典(或是Item对象)保存为文件或者保存在数据库中。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

scrapy.spider.Spider类介绍

常用类属性文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

name:是字符串。标识了每一个spider的名字,必须定义且唯一。实际中我们一般为每个独立网站创建一个spider。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

start_url:是包含初始请求页面url的列表,必须定义。start_requests()方法会引用该属性,发出初始的Request。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

custom_settings:是一个字典,每一条键值对表示一个配置,可用于覆写SETTINGS(Scrapy的全局配置模块,位于settings.py文件中)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

例:custom_settings = {'COOKIES_ENABLED': True,'ROBOTSTXT_OBEY': False}。覆盖了全局属性COOKIES_ENABLED。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

扩展:设置settings中的值的几种方法,优先级从高到低如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

1. 命令行选项文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

2. custom_settings文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

3. settings.py文件文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

4. 命令行的默认设置,每一个命令行都有它自己的默认设置文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

5. 默认的全局设置,被定义在 scrapy.settings.default_settings 中文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

allowed_domains:是一个字符串列表。规定了允许爬取的网站域名,非域名下的网页将被自动过滤。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

例:allowed_domains = cnblogs.com,start_url = 'zhihu.com'。在这个例子中,知乎不属于CSDN的域名,因此爬取过程中会被过滤。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

crawler:是一个Crawler对象。可以通过它访问Scrapy的一些组件(例如:extensions, middlewares, settings)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

例:spider.crawler.settings.getbool('xxx')。这个例子中我们通过crawler访问到了全局属性。settings:是一个Settings对象。它包含运行中时的Spider的配置。这和我们使用spider.crawler.settings访问是一样的。logger:是一个Logger对象。根据Spider的name创建的,它记录了事件日志。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

常用方法文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

start_requests:该方法是Spider的入口方法。默认下,该方法会请求start_url中定义的url,返回对应的Request,如果该方法被重写,可以返回包含**Request(作为第一个请求)的可迭代对象或者是FormRequest对象**,一般POST请求重写该方法。parse:当其他的Request没有指定回调函数时,用于处理下载响应的默认回调,主要作用:负责解析返回的网页数据(response.body),提取结构化数据(生成item)生成需要下一页的URL请求。该方法用于编写解析网页的具体逻辑(包含解析数据,或是解析出新的页面),所以此方法非常重要哦!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

Spider案例:披荆斩棘的哥哥评论

最近被披荆斩棘的哥哥所吸引,但是还是要为大家做好服务,每天更新文章啊!介绍下这个综艺节目哈。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

《披荆斩棘的哥哥》是芒果TV推出的全景音乐竞演综艺。节目嘉宾们彼此挑战,披荆斩棘,通过男人之间的彼此探索、家族建立的进程,诠释“滚烫的人生永远发光”,见证永不陨落的精神力。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

我们本次使用Scrapy爬取哥哥们的评论。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

Scrapy框架开发爬虫入门:Spider是什么?

分析思路:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

打开谷歌浏览器,访问第01期的链接(mgtv.com/b/367750/13107),把JavaScript加载关掉,刷新,发现底下的评论数据没有了,说明这数据是异步加载的,在这个网页链接的源代码里是找不到评论数据的;文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

既然是异步加载,那么就要抓包了。把刚刚关掉的JavaScript打开,重新加载网页,右键检查,Network, 数据一般都在XHR或者JS里面,所以先把这两项勾选了,这时候点击评论的下一页,发现数据就在JS里面:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

Scrapy框架开发爬虫入门:Spider是什么?
Scrapy框架开发爬虫入门:Spider是什么?

由上面评论的真实链接可以知道,评论真实的请求网址是:“comment.mgtv.com/v4/com”,后面跟着一系列的参数(callback, _support, subjectType, subjectId, page, _),可见:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

Scrapy框架开发爬虫入门:Spider是什么?

我们知道page是页码数,subjectId是s每个视频对应的id,callback回调函数,最后一个大胆猜测下就是unix时间戳后面再加上3位随机数(或者unix时间戳乘以1000再取整),应该只起一个占位的作用,可能是一个完全没用的参数,只是用来吓唬我们的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

但是不确定,我们来看一下,于是我去掉最后一个参数在浏览器发出了一下请求,结果如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

Scrapy框架开发爬虫入门:Spider是什么?

说明就是一个完全没用的参数,哈哈哈用来吓唬我们的,不要怕!我们不用它。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

链接有了之后我们就开始创建爬虫项目啦!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

首先打开命令行,输入:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

scrapy startproject mongotv_comments_crawler

生成新的mongotv_comments_crawler项目,再输入:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

cd mongotv_comments_crawler
scrapy genspider mgtv_crawl mgtv.com

生成爬虫名。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

然后,用PyCharm打开项目。由于最后爬取到的是json数据,我们直接解析Json数据,并返回到Items中。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

因此在爬虫文件mgtv_crawl.py的MgtvCrawlSpider类中,进行如下定义:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

class MgtvCrawlSpider(scrapy.Spider):
    name = 'mgtv_crawl'
    allowed_domains = ['mgtv.com']
    # start_urls = ['http://mgtv.com/'] 因为我们每次都需要构建芒果TV的请求,所以我们重写start_requests方法
    subject_id = 4327535  # 视频的id
    pages = list(range(1, 100))  # 需要爬取的评论页数比如100页

因为我们要爬取多页的内容,所以我们要不断修改page参数,所以我们重写start_requests方法文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

    def start_requests(self):  # 重写start_requests
        start_urls = [f'https://comment.mgtv.com/v4/comment/getCommentList?page={page}&subjectType=hunantv2014&subjectId={self.subject_id}&callback=jQuery18204988030991528978_1630030396693&_support=10000000&_=1630030399968' for page in self.pages]
        # 生成所有需要爬取的url保存进start_urls
        for url in start_urls:  # 遍历start_urls发出请求
            yield Request(url)

然后重写parse()函数,获取json结果。但是json结果前面有下图一样的前缀内容,我们要去掉文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

Scrapy框架开发爬虫入门:Spider是什么?
    def parse(self, response):
        text = response.text[response.text.find('{'):-1]  # 通过字符串选取的方式把"jQuery...()去掉"
        json_data = json.loads(text)  # 转换成json格式

        for i in json_data['data']['list']:  # 遍历每页的评论列表
            item = MongotvCommentsCrawlerItem()
            item['content'] = i['content']
            item['commentId'] = i['commentId']
            item['createTime'] = i['createTime']
            item['nickName'] = i['user']['nickName']
            yield item

编写item,获取评论的:内容、创建时间、用户名和评论ID文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

class MongotvCommentsCrawlerItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    content = scrapy.Field()
    createTime = scrapy.Field()
    nickName = scrapy.Field()
    commentId = scrapy.Field()

然后便是写pipelines.py文件,把爬取回来的items入库文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

import pymysql


class MongotvCommentsCrawlerPipeline(object):
    def __init__(self):
        self.conn = pymysql.connect(host='127.0.0.1', user='root', password='root',
                                    db='mgtv', charset='utf8')

    def process_item(self, item, spider):
        commentId = item["commentId"]
        content = item['content']
        createTime = item['createTime']
        nickName = item["nickName"]

        sql = "insert into comments(commentId,content,createTime,nickName) values(" + str(commentId) + ",'" + content + "','" + createTime + "','" + nickName + "');"
        self.conn.query(sql)
        self.conn.commit()
        return item

    def close_spider(self, spider):
        self.conn.close()

在settings.py中开启对应的设置项:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

Scrapy框架开发爬虫入门:Spider是什么?

开启爬虫进行爬取:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

scrapy crawl mgtv_crawl

爬取到的结果如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html

Scrapy框架开发爬虫入门:Spider是什么?
文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunda/28290.html
  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/yunda/28290.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定