Scrapy创建简单的爬取任务

参考:https://scrapy-chs.readthedocs.io/zh_CN/latest/intro/tutorial.html#intro-tutorial

快速开始

利用scrapy来创建任务,爬取王者荣耀的英雄头像。

下载scrapy

pip install scrapy

创建一个项目

scrapy startproject king_head

目录结构

$ tree
.
├── king_head
│   ├── __init__.py
│   ├── __pycache__
│   ├── items.py                  # 项目中item文件,保存爬取数据的容器
│   ├── middlewares.py
│   ├── pipelines.py              # 用来对items里面提取的数据做进一步处理,如保存等
│   ├── settings.py               # 项目设置文件
│   └── spiders                   # 爬取脚本所在目录
│       ├── __init__.py
│       └── __pycache__
└── scrapy.cfg                    # 项目配置文件

4 directories, 7 files

编写第一个爬虫

在spiders目录下创建我们的第一个爬虫。

我们创建一个爬虫,必须继承scrapy.Spider类,并且需要定义以下三个属性:

  • name: 用于区别Spider。该名字必须唯一
  • start_urls: 包含Spider在启动时进行爬取的url列表。因此,第一个被获取到的页面将是其中之一。 后续的URL则从初始的URL获取到的数据中提取。
  • parse(): Spider的一个方法,被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。

假设爬取王者荣耀的英雄头像

编写items文件

import scrapy

class HeroItem(scrapy.Item):
    # 抓取的内容
    name = scrapy.Field()  
    url = scrapy.Field()

上面类中的name,url就像是字典中的“键”,爬到的数据就像似字典中的“值”。

编写spider文件

 from scrapy.spiders import CrawlSpider
    from king_head.items import HeroItem
    
    
    class Spider(CrawlSpider):   
        name = 'hero_head'                  # 爬虫的名字,必须唯一
        allowed_domains = ['pvp.qq.com']    # 爬取的域名
        start_urls = ['https://pvp.qq.com/web201605/herolist.shtml']    # 爬取URL
    
        def parse(self, response):      # 回调函数,处理response并返回处理后的数据和需要跟进的url
            for line in response.xpath('//ul[@class="herolist clearfix"]/li'):
                # 初始化item存储爬取的信息
                item = HeroItem()
                item["name"] = line.xpath('a[@target="_blank"]/img/@alt').extract()
                item["url"] = line.xpath('a[@target="_blank"]/img/@src').extract()
    
                yield item                  # 生成式

开始爬取命令

scrapy crawl hero_head -o item.json    # -o 指定保存到文件

程序运行到这里可以获取到头像和url,并且存储到本地的json文件中。

问题

  1. 爬取后的中文的显示乱码
   # 修改settings.py文件,添加编码格式,支持utf8
   FEED_EXPORT_ENCODING = 'UTF-8'

持久化

下面我们将获取到的内容写入到数据库,包括英雄的名字和头像的链接地址

首先需要在settings.py配置文件中开启通道


 ITEM_PIPELINES = {
       'king_head.pipelines.KingHeadPipeline': 300,
    }
    
    MYSQL_HOST = '127.0.0.1'
    MYSQL_PORT = 3306
    MYSQL_USER = 'root'
    MYSQL_PWD = '123456'
    MYSQL_DB = 'test'

编写pipelines.py,将结果写入数据库

  import pymysql
    
    
    class KingHeadPipeline(object):
        def __init__(self):
            '''
            初始化方法
            '''
            # 创建数据库链接
            self.client = pymysql.Connect(
                '127.0.0.1', 'root', '12345678','test', 3306, charset='utf8'
            )
            # 创建游标
            self.cursor = self.client.cursor()
    
        def open_spider(self, spider):
            '''
            爬虫启动的时候会调用一次
            :param spider:
            :return:
            '''
            print('爬虫开启')
            pass
    
        def process_item(self, item, spider):
            '''
            这个方法必须实现,爬虫文件中所有的item 都会经过这个方法
            :param item: 爬虫文件传递过来的item对象
            :param spider: 爬虫文件实例化的对象
            :return:
            '''
            # 存储到本地json文件
            data_dict = dict(item)
    
            # 插入数据库
            sql = "insert into hero_info(%s,%s)  values('%s','%s')" % ("hero_name", "hero_url", data_dict["name"][0], "https:" + data_dict["url"][0])
            try:
                self.cursor.execute(sql)
                self.client.commit()
            except Exception as err:
                self.client.rollback()
                print(err)
    
            # 如果有多个管道文件,一定要return item , 否则下一管道无法接收到item
            print('经过了管道')
            return item
    
        def close_spider(self, spider):
            '''
            爬虫结束的时候调用一次
            :param spider:
            :return:
            '''
            # self.file.close()
            self.client.close()
            self.cursor.close()
            print('爬虫结束')

编写pipelines.py,根据请求到的URL去下载图片

  import pymysql
    from urllib import request
    import  ssl
    
    ssl._create_default_https_context = ssl._create_unverified_context
    
    class KingHeadPipeline(object):
        def __init__(self):
            '''
            初始化方法
            '''
            # 创建数据库链接
            self.client = pymysql.Connect(
                '127.0.0.1', 'root', '12345678','test', 3306, charset='utf8'
            )
            # 创建游标
            self.cursor = self.client.cursor()
    
        def open_spider(self, spider):
            '''
            爬虫启动的时候会调用一次
            :param spider:
            :return:
            '''
            print('爬虫开启')
            pass
    
        def process_item(self, item, spider):
            '''
            这个方法必须实现,爬虫文件中所有的item 都会经过这个方法
            :param item: 爬虫文件传递过来的item对象
            :param spider: 爬虫文件实例化的对象
            :return:
            '''
            # 存储到本地json文件
            data_dict = dict(item)
    
            request.urlretrieve("https:" + data_dict["url"][0], r"images/%s.jpg" % (data_dict["name"][0]))
            # 如果有多个管道文件,一定要return item , 否则下一管道无法接收到item
            print('经过了管道')
            return item
    
        def close_spider(self, spider):
            '''
            爬虫结束的时候调用一次
            :param spider:
            :return:
            '''
            # self.file.close()
            self.client.close()
            self.cursor.close()
            print('爬虫结束')

你可能感兴趣的:(Python)