美文网首页
3.Scrapy 入门案例

3.Scrapy 入门案例

作者: XiWeidong | 来源:发表于2018-03-17 19:01 被阅读0次

    一 【学习目标】

    • 创建一个Scrapy项目
    • 定义提取的结构化数据Item
    • 编写爬虫网页的Spider并提取出结构化数据Item
    • 编写Item Pipelines 来存储提取的Item数据(可以存储到MySQL或Redis)

    二 【新建一个新的项目】

    1. 新建一个项目,并进入项目目录。
    scrapy startproject mySpider
    cd mySpider
    
    image.png

    项目中文件的作用:

    • scrapy.cfg : 项目的配置文件
    • mySpider:项目的模块,放项目相关的代码文件
    • mySpider/items.py:项目的数据机构存储文件
    • mySpider/pipelines.py:项目的管道文件
    • mySpider/settings.py:项目的设置文件
    • mySpider/spiders:放置爬虫程序的目录,多个爬虫就多个子目录

    三【设置数据结构】
    这里我打算取的地址是:
    http://www.dytt8.net/html/gndy/dyzz/list_23_1.html
    获取所有电影的标题、链接、描述和下载地址

    1. 打开mySpider目录下的Items.py

    2. 定义电影的结构化数据的字段,用于保存获取到的数据。

    3. 可以通过创建一个scrapy Item 类,并且类型为Scrapy.Field来定义一个Item。

    4.下面我们创建一个MyspiderItem和构建Item的属性。

    import scrapy
    
    
    class MyspiderItem(scrapy.Item):
        # define the fields for your item here like:
        title = scrapy.Field()
        link = scrapy.Field()
        desc = scrapy.Field()
        download_url = scrapy.Field()
        pass
    

    四【制作爬虫】
    1.创建一个爬虫文件

    scrapy genspider movie www.dytt8.net
    

    2.修改spider/movie.py 文件,内容如下:

    # -*- coding: utf-8 -*-
    import scrapy
    
    
    class MovieSpider(scrapy.Spider):
        name = 'movie'
        allowed_domains = ['www.dytt8.net']
        start_urls = ['http://www.dytt8.net/']
    
        def parse(self, response):
            pass
    

    这个文件也可以手动创建,用命令比较方便一些。

    • name : 这个是爬虫的名称,必须唯一。

    • allow_domains : 是允许的域名范围,是一个列表类型,可以设置多个域名,表示爬虫只能爬取允许域名下URL。

    • start_urls : 爬虫从这里定义的URL开始爬取网页。

    • parse(self,response) : 爬取网页后,使用这个方法来处理爬取后获取的网页内容。
      a. 提取页面数据组装结构化数据Item
      b.获取下一个需要爬取的URL

    3.在start_urls里加入一个需要爬取的url地址

    start_urls = ['http://www.dytt8.net/html/gndy/dyzz/index.html']
    
    1. 修改parse方法
    def parse(self, response):
            with open("movie_items.html","w") as fp:
                fp.write(response.text)
            pass
    

    5.运行一下items爬虫

    scrapy crawl movie
    

    会生成movie_items.html页面

    1. 取结构化数据
      一般使用xpath,教程参考:http://www.w3school.com.cn/xpath/index.asp
      修改movie.py爬虫文件
    # -*- coding: utf-8 -*-
    import scrapy
    from mySpider.items import MyspiderItem
    import json
    import time
    import time
    class MovieSpider(scrapy.Spider):
        name = 'movie'
        page = 1
        base_url = "http://www.dytt8.net"
        list_base_url = base_url + '/html/gndy/dyzz/list_23_'
        allowed_domains = ['www.dytt8.net']
        start_urls = [list_base_url + "%s.html" % page]
        #电影列表回调方法
        def parse(self, response):
            #通过xpath获取电影列表
            titlelist = response.xpath('//table[@class="tbspan"]')
            for movie in titlelist:
                item = MyspiderItem()
                title = movie.xpath("./tr[2]/td[2]/b/a/text()").extract() #通过子节点提取标题
                link = movie.xpath("./tr[2]/td[2]/b/a/@href").extract()#通过子节点提取详情url
                desc = movie.xpath("./tr[4]/td/text()").extract() #通过子节点提取电影描述
                item['title'] = title[0] #提取后是一个只有一个元素的列表类型,所以提取第0个元素
                item['link'] = self.base_url + link[0]
                item['desc'] = desc[0]
                item['download_url'] = ''
                yield item
                #通过 item['link'] 属性获取详情页,处理方法为self.parse_detail
                yield scrapy.Request(item['link'],callback=self.parse_detail)
    
            #继续爬取下一页以及后面的页面,一共3页
            if self.page < 3:
                self.page = self.page + 1
                page_url = self.list_base_url + "%s.html" % self.page
                print("---------------------------page number url ----------------------------")
                print(page_url)
                yield scrapy.Request(page_url, callback=self.parse)
    
        # 电影详情回调方法
        def parse_detail(self,response):
            time.sleep(2)
            #通过xpath获取电影详情里的下载地址
            download_url = response.xpath('//*[@id="Zoom"]//table[1]//td/a/@href').extract()
            print("---------------------------detail download_url----------------------------")
            print("---------------------------" + download_url[0] + "----------------------------")
            item = MyspiderItem()
            item['link'] = response.url
            item['download_url'] = download_url[0]
            return item
    
    
    1. 保存数据
      创建表:
    DROP TABLE IF EXISTS `movies`;
    CREATE TABLE `movies` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `title` varchar(50) NOT NULL DEFAULT '',
      `link` varchar(200) NOT NULL DEFAULT '',
      `desc` varchar(1024) NOT NULL DEFAULT '',
      `download_url` varchar(500) DEFAULT '',
      PRIMARY KEY (`id`),
      KEY `link` (`link`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
    

    然后修改pipelines.py管道文件

    # -*- coding: utf-8 -*-
    
    # Define your item pipelines here
    #
    # Don't forget to add your pipeline to the ITEM_PIPELINES setting
    # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
    import json
    import pymysql
    import redis
    import jieba
    from collections import Counter
    
    class MyspiderPipeline(object):
        def __init__(self):
            self.id = 1;
            #链接数据库
            self.db = pymysql.connect("localhost", "root", "root", "test", charset='utf8')
            #获取游标
            self.cursor = self.db.cursor()
            #链接redis
            self.redisClient = redis.Redis(host="127.0.0.1", port=6379)
    
        def process_item(self, item, spider):
            dictitem = dict(item)
            #通过download_url判断,如果是详情页获取的item,把获取到的电影下载地址download_url更新到mysql数据库
            if dictitem['download_url']:
                link = dictitem['link']
                download_url = dictitem['download_url']
                sql = "UPDATE movies SET `download_url` = '%s' WHERE `link` = '%s'" \
                      % (download_url, link)
                self.cursor.execute(sql)
            # 如果是电影列表获取的item,把获取到的title,link,desc插入到mysql数据库
            else:
                title = dictitem['title']
                link = dictitem['link']
                desc = dictitem['desc']
                sql = "INSERT INTO movies(`title`,`link`,`desc`) \
                                                           VALUES ('%s', '%s', '%s')" % \
                      (title, link, desc)
                self.cursor.execute(sql)
                last_id = self.cursor.lastrowid #获取最后一次插入的主键id
                #用jieba对title进行分词,把分词和结果和主键的保存到redis的set数据类型里,用于搜索
                data = jieba.cut(title)
                data = dict(Counter(data))
                for k, v in data.items():#循环所有分词
                    word = k.encode('utf-8')
                    self.redisClient.sadd(word, last_id)#保存每个分词和id的对应关系
    
            print("--------------------------- process_item sql ----------------------------")
            print(sql)
            self.db.commit()
            return item
    
    

    需要安装第三方模块:

    pip install pymysql
    pip install redis
    pip install jieba
    

    相关文章

      网友评论

          本文标题:3.Scrapy 入门案例

          本文链接:https://www.haomeiwen.com/subject/gaeqqftx.html