MyException - 我的异常网
当前位置:我的异常网» 开源软件 » 150行代码写爬虫(1)

150行代码写爬虫(1)

www.MyException.Cn  网友分享于:2018-04-03  浏览:2次
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

文章评论

要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
如何成为一名黑客
如何成为一名黑客
我是如何打败拖延症的
我是如何打败拖延症的
 程序员的样子
程序员的样子
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
为什么程序员都是夜猫子
为什么程序员都是夜猫子
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
旅行,写作,编程
旅行,写作,编程
程序员都该阅读的书
程序员都该阅读的书
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
那些争议最大的编程观点
那些争议最大的编程观点
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
中美印日四国程序员比较
中美印日四国程序员比较
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
鲜为人知的编程真相
鲜为人知的编程真相
程序员必看的十大电影
程序员必看的十大电影
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
总结2014中国互联网十大段子
总结2014中国互联网十大段子
一个程序员的时间管理
一个程序员的时间管理
程序员和编码员之间的区别
程序员和编码员之间的区别
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
每天工作4小时的程序员
每天工作4小时的程序员
漫画:程序员的工作
漫画:程序员的工作
编程语言是女人
编程语言是女人
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
10个调试和排错的小建议
10个调试和排错的小建议
程序员应该关注的一些事儿
程序员应该关注的一些事儿
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
程序员的鄙视链
程序员的鄙视链
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
Java程序员必看电影
Java程序员必看电影
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有