150行代码写爬虫(一)
程序员文章站
2022-06-17 09:29:19
...
目的:爬取某视频网站的所有视频;
工具:scrapy、MySQL、python 2.7;
项目地址:https://gitee.com/dushen666/spider.git;
scrapy是一个python的爬虫框架,有兴趣的同学可以了解一下,本篇我将介绍如何用scrapy从零开始编写一个爬虫;
步骤↓
- 安装python 2.7,并配置好环境变量 ,此处不多说。
- 安装scrapy:
pip install Scrapy
若没有pip请自行安装 - 构建一个scrapy项目:进入想要保存项目的路径,执行以下代码:
scrapy startproject spider
可以看到当前目录下已经生成了该项目,将项目导入pycharm,项目结构如下:
- 在spiders路径下建立我们的爬虫:
模块中的内容稍后再介绍!
- 建立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) - 之后就是编写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>
<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>
-
通过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的使用方法可以查看官方文档。 -
编辑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 用于处理视频详情页 - 执行爬虫,进入项目根路径,执行以下命令:
scrapy crawl h6080spider -o result.json
可以看到路径下生成了result.json,该文件以json的形式存储了H6080MovieInfo和H6080Item
到此一个爬虫就已经可以工作了,但是这还远远不行,我们要把爬取的信息存储到数据库中,并且要实现去重功能,否则会产生大量重复数据,关于去重和数据库存储我会在下一篇文章中介绍。
最后再次附上项目地址:https://gitee.com/dushen666/spider.git