`

150行代码写爬虫(一)

阅读更多

目的:爬取某视频网站的所有视频;

工具:scrapy、MySQL、python 2.7;

项目地址:https://gitee.com/dushen666/spider.git

scrapy是一个python的爬虫框架,有兴趣的同学可以了解一下,本篇我将介绍如何用scrapy从零开始编写一个爬虫;

步骤↓

  1. 安装python 2.7,并配置好环境变量 ,此处不多说。
  2. 安装scrapy:
    pip install Scrapy
     若没有pip请自行安装
  3. 构建一个scrapy项目:进入想要保存项目的路径,执行以下代码:
    scrapy startproject spider
     可以看到当前目录下已经生成了该项目,将项目导入pycharm,项目结构如下:
  4. 在spiders路径下建立我们的爬虫: 

    模块中的内容稍后再介绍!

  5. 建立items,用于保存爬取来的信息,修改items.py:
    import scrapy
    
    class H6080Item(scrapy.Item):
        name = scrapy.Field()
        url = scrapy.Field()
        num = scrapy.Field()
    
    
    class H6080MovieInfo(scrapy.Item):
        name = scrapy.Field()
        director = scrapy.Field()
        actor = scrapy.Field()
        types = scrapy.Field()
        area = scrapy.Field()
        publishtime = scrapy.Field()
        countnumber = scrapy.Field()
        introduce = scrapy.Field()
        picurl = scrapy.Field()
     说明:用过Django的同学可以看出,item与Django的model有点类似,但是item并没有区分那么多的数据类型,使用起来很方便。此处H6080Item用于保存视频名、视频url和该视频是哪一集,H6080MovieInfo用于保存视频名、主演、导演、海报url等信息。(因为我要爬取www.h6080.com上的视频,所以我将items命名为H6080Item和H6080MovieInfo)
  6. 之后就是编写spider的内容了,在此之前我们先分析一下要爬取的页面:
     打开要爬取的主页www.h6080.com,我们可以分析出,该网站主要有四个页面:主页、分类展示页、视频详情页和播放页。他们的url形式如下:
    主页 www.h6080.com  
    分类展示页 www.h6080.com/type/2/3.html 2为类别id,3为页码数
    视频详情页 www.h6080.com/show/36088.html 36088为视频id
    播放页 www.h6080.com/play/36088/1/5.html 36088为视频id,5为集数

    可以看出我们要的H6080Item中的信息均在播放页中,H6080MovieInfo中的信息均在视频详情页中。接下来我们分析这两个页面的HTML源码:

    视频详情页中,所要的主演、导演等信息均在这个<table>中:

    <table class="table table-striped table-condensed table-bordered" style="margin-bottom:10px;font-size:12px;">
    <tbody>
    <tr>
        <td class="span2"><span class="info-label">导演</span></td>
        <td>金晔</td>
    </tr>
    <tr>
        <td class="span2"><span class="info-label">主演</span></td>
        <td id="casts" style="position:relative;">杨子姗 / 郑恺 / 张国立 / 江珊 / 田雷 / 钟楚曦 / 逯子 / 周宸佳 / 王森 / 高晓菲 / 刘立<a class="casts-swith"></a></td>
    </tr>
    <tr>
        <td class="span2"><span class="info-label">类型</span></td>
        <td>剧情 / 爱情</td>
    </tr>
    <tr>
        <td class="span2"><span class="info-label">制片国家</span></td>
        <td>中国大陆</td>
    </tr>
    <tr>
        <td class="span2"><span class="info-label">更新状态</span></td>
        <td>更新至10集 / 共42集</td>
    </tr>
    <tr>
        <td class="span2"><span class="info-label">上映日期</span></td>
        <td>2018-03-26(中国大陆)</td>
    </tr>
    <tr>
    <td class="span2"><span class="info-label">评分</span></td>
    <td>豆瓣:<a rel="nofollow" class="score" target="_blank" href="/">3.0 <i class="glyphicon glyphicon-new-window"></i></a></td>
    </tr>
    </tbody>
    </table>
    

     视频名和海报图片url分别在<h1 class="movie-title">和<img class="img-thumbnail">中:

        <div class="col-md-12">
            <h1 class="movie-title">好久不见2018 <span class="movie-year">(2018)</span></h1>
        </div>
        
        <div class="col-md-9">
            <div class="row">
                <div class="col-md-4" style="padding-right:5px;">
                <a href="/show/41134.html" style="display:block;position:relative;">
                <img class="img-thumbnail" alt="好久不见2018" width="100%" src="http://wx2.sinaimg.cn/mw690/80df6fe6gy1fpqpi212ylj20u019zdlv.jpg">
                    <button class="hdtag">更新至10集 / 共42集</button>
    			</a>
    			<div class="online-button">
                    <a target="_blank" class="btn btn-success btn-block" href="/play/41134.html">立即播放</a>
                </div>
                <div class="col-md-6 left-bt" data-toggle="modal" data-target="#addresource">
                    <i class="glyphicon glyphicon-pencil"></i> 发布
                </div>
                <div class="col-md-6 icon-heart left-bt" id="add_fav" onclick="add_fav(1)">
                    <i class="glyphicon glyphicon-heart"></i> 喜欢
                </div>
    
     

     

     播放页中,视频url在<iframe>的src中,视频名和集数在<h3 class="movie-title">中:
        <div class="container-fluid" style="padding-top:15px;background:#FFF;position:relative">
            <h3 class="movie-title">视频名称:好久不见2018 - 第03集</h3>
          <div class="player" id="player">
    <iframe border="0" frameborder="0" height="460" marginheight="0" marginwidth="0" scrolling="no" src="http://api.tianxianle.com/jx/dapi.php?id=qKt1naKhqaajnnBomZNmbWFi" width="100%" allowfullscreen="true" allowtransparency="true"></iframe></div>
    
     
  7. 通过scrapy的命令行工具和选择器(Selectors)调试提取所需信息的语句。先提取详情页的信息,执行以下语句进入命令行工具: 

    scrapy shell "http://www.h6080.com/show/40928.html"
     

     先提取视频名:视频名在<h1 class="movie-title">中,在命令行工具中输入以下代码:
    In [1]: response.xpath('//h1[@class="movie-title"]/text()').extract()[0]
    Out[1]: u'\u9006\u6c34\u5bd2 '
     说明://h1表示取该responsebody的所有<h1>,[@class="movie-title"]表示筛选所有class为movie-title的标签,/text()表示取标签中的内容,extract()的作用是将结果转为list并返回,[0]表示取list[0]。此处只举这一个例子,其他信息的提取方法不多说,若要详细了解selector的使用方法可以查看官方文档。

     

  8. 编辑spider的内容:
    # -*- coding: utf-8 -*-
    """
        Created by 杜神 at 2018/3/21
    """
    import sys
    reload(sys)
    sys.setdefaultencoding('utf-8')
    from spider.items import H6080Item, H6080MovieInfo
    from scrapy.contrib.spiders import CrawlSpider, Rule
    from scrapy.contrib.linkextractors import LinkExtractor
    import logging
    import re
    
    class SpiderNo1(CrawlSpider):
        name = 'h6080spider'
        allowed_domains = ['h6080.com']
        start_urls = [
            'http://www.h6080.com',
        ]
        logging.getLogger("requests").setLevel(logging.WARNING
                                               )  # 将requests的日志级别设成WARNING
        logging.basicConfig(
            level=logging.DEBUG,
            format=
            '%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
            datefmt='%a, %d %b %Y %H:%M:%S',
            filename='h6080spider.log',
            filemode='w')
    
        rules = (
            # follow所有分类链接/下一页链接/详情页链接
            Rule(LinkExtractor(allow=('\/type\/\d+\.html', '\/type\/\d+\/\d+\.html')), follow=True),
            Rule(LinkExtractor(allow=('play\/\d+\/\d+\/\d+\.html', )), callback='parse_item'),
            Rule(LinkExtractor(allow=('\/show\/\d+\.html', )), callback='parse_movie_info', follow=True),
        )
    
        def parse_item(self, response):
            item = H6080Item()
            item['name'] = response.xpath('//h3[@class="movie-title"]/text()').extract()[0]
            item['url'] = response.xpath('//div[@class="player"]/iframe/@src').extract()[0]
            item['num'] = re.findall('\/\d+\.html', response.url)[0].split('.')[0][1:]
            self.log('find a url! %s' % response.url)
            yield item
    
        def parse_movie_info(self, response):
            item = H6080MovieInfo()
            rows = response.xpath('//td/text()').extract()
            item['director'] = rows[0]
            item['actor'] = rows[1]
            item['types'] = rows[2]
            item['area'] = rows[3]
            try:
                item['publishtime'] = rows[5]
            except Exception:
                item['publishtime'] = '1999-01-01'
            item['name'] = response.xpath('//h1[@class="movie-title"]/text()').extract()[0]
            item['introduce'] = response.xpath('//p[@class="summary"]/text()').extract()[0]
            item['picurl'] = response.xpath('//img[@class="img-thumbnail"]/@src').extract()[0]
            if len(re.findall('\d+', rows[4])) > 0:
                item['countnumber'] = re.findall('\d+', rows[4])[0]
            else:
                item['countnumber'] = 0
            self.log('find a movie! %s' % item['name'])
            yield item
    
     说明:此处继承scrapy的CrawlSpider类,
    name 给该spider取个唯一的名字,此处取名h6080spider
    allowed_domains 允许爬虫访问的域名
    start_urls 爬虫起始url
    logging 日志,不多说
    rules

    Rule(LinkExtractor(allow=('play\/\d+\/\d+\/\d+\.html', )), callback='parse_item')

    若url匹配正则表达式,则由callback指定的方法处理,若未指定,则不处理。follow=True表示是否跟进,默认为True

    parse_item

    用于处理播放页

    parse_movie_info 用于处理视频详情页
  9. 执行爬虫,进入项目根路径,执行以下命令:
    scrapy crawl h6080spider -o result.json
     可以看到路径下生成了result.json,该文件以json的形式存储了H6080MovieInfo和H6080Item

 到此一个爬虫就已经可以工作了,但是这还远远不行,我们要把爬取的信息存储到数据库中,并且要实现去重功能,否则会产生大量重复数据,关于去重和数据库存储我会在下一篇文章中介绍。

 

最后再次附上项目地址:https://gitee.com/dushen666/spider.git

1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics