day73-scrapy框架使用

1scrapy的使用

1.1scrapy爬取数据流程

scrapy由5个模块构成,分别是engine(引擎),spiders(爬虫),scheduler(调度),downloader(爬取),item pipelines(管道)
Scrapy中的数据流由执⾏行行引擎控制,其过程如下: 1、引擎打开一个网站(open a domain),找到处理理该⽹网站的Spider并向该spider请求第一个要 爬取的URL(s)。 2、引擎从Spider中获取到第一个要爬取的URL并在调度器(Scheduler)以Request调度。 3、引擎向调度器请求下一个要爬取的URL。 4、调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求(request)⽅方向)转 发给下载器(Downloader)。 5、一旦⻚页⾯面下载完毕,下载器⽣生成⼀一个该⻚页⾯面的Response,并将其通过下载中间件(返回 (response)⽅方向)发送给引擎。 6、引擎从下载器中接收到Response并通过Spider中间件(输⼊入⽅方向)发送给Spider处理理。 7、Spider处理理Response并返回爬取到的Item及(跟进的)新的Request给引擎。 8、引擎将(Spider返回的)爬取到的Item给Item Pipeline,将(Spider返回的)Request给调度 器。 9、(从第二步)重复直到调度器中没有更更多地request,引擎关闭该⽹网站。

1.2scrapy安装

linux中直接跳过windows安装过程中的一二步(见下)
windows中需要安装其他插件;过程如下:
1.进入http://www.lfd.uci.edu/~gohlke/pythonlibs/;搜索Twisted
然后在cmd中输入python查看python版本及计算机为多少位(本次选择3.6版本64位);
本次下载Twisted-18.9.0-cp36-cp36m-win_amd64.whl版本
2.在cmd中进入存放虚拟环境的文件夹使用activate激活环境;然后退到存放第一步所下载的文件的文件夹。使用命令pip install Twisted-18.9.0-cp36-cp36m-win_amd64.whl将其安装到虚拟环境;
3.安装pypiwin32 :pip install pypiwin32
4.安装scrapy: pip install scrapy

1.3创建项目及spider

创建项目:命令行中输入scrapy startproject 项目名称
如scrapy startproject sinanews
进入项目后创建spider: 命令行中输入 scrapy genspider 名称 去掉http://的域名
如scrapy genspider sport sports.sina.com.cn

1.4配置项目

打开项目后将settings中的ROBOTSTXT_OBEY = True改为ROBOTSTXT_OBEY = False;
在最后添加编码格式:FEED_EXPORT_ENCODING = 'utf-8'
运行spider文件:scrapy crawl sina -o result.json表示运行spider文件sina并将爬取数据存放到result.json文件中(会自动创建该文件),存放数据的类型有json、csv、xml及pickle
scrapy crawl sina表示运行spider文件sina;但不将结果保存到本地。
spider文件部分参数的作用
allowed_domains: 允许爬取的域名;start_urls: Spider启动时爬取的url列表 ;parse: 负责解析返回的响应,提取数据或进一步处理理
item文件的作用
Item是保存爬取数据的容器

2mysql使用

python中的eval用法
eval(字符串) 能将字符串当成程序运行
mysql中清空数据库的两种方法及区别
truncate table manhua清空数据库,若添加新数据id从1开始
delete from manhau清空数据库,若添加新数据id将从之前的后面接着续

3一个简单的scrapy项目-sinanews(get请求)

spider文件中爬取数据

import scrapy
from sinanews.items import SinanewsItem        
class SinaSpider(scrapy.Spider):
    name = 'sina'
    allowed_domains = ['sports.sina.com.cn']
    start_urls = ['http://sports.sina.com.cn/']    
    def parse(self, response):
        reult=response.selector.css('.ty-card-type10-makeup a::text').extract()
        for title in reult:
            item = SinanewsItem()
            item['title'] = title
            yield item

items文件中保存数据

import scrapy        
class SinanewsItem(scrapy.Item):
    title = scrapy.Field()

reult=response.selector.css('.ty-card-type10-makeup a::text').extract()该句表示获取class为该类型下的a标签中的text内容返回一个对象,后面接extract()表示获取其中的内容。

4爬取虎扑网站数据(get请求)

scrapy中处理数据用Selector选择器;其基于lxml构建,支持xpath, css, 正则表达式匹配

import scrapy
from hupu.items import HupuItem        
class SproteSpider(scrapy.Spider):
    name = 'sprote'
    allowed_domains = ['bbs.hupu.com']
    start_urls = ['http://bbs.hupu.com/gear/']    
    # 构造请求
    def start_requests(self):
        headers = {
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)',
            'Accept': 'application/json, text/plain, */*',
            'Accept-Encoding': 'gzip, deflate, sdch',
            'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4,zh-TW;q=0.2,mt;q=0.2',
            'Connection': 'keep-alive',
            'X-Requested-With': 'XMLHttpRequest',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        }
        for page in range(1, 101):
            yield scrapy.Request(url='http://bbs.hupu.com/gear-%d' % page,
                                 headers=headers,
                                 method='GET',
                                 callback=self.parse,
                                 )

    # 解析响应
    def parse(self, response):
        result_list = response.selector.css('.for-list li')
        for index in result_list:
            item = HupuItem()
            title = index.css('.truetit::text').extract_first()
            author = index.css('.aulink::text').extract_first()
            ti_date = index.css('.author.box').xpath('./a[2]/text()').extract_first()
            item['title'] = title
            item['author'] = author
            item['ti_date'] = ti_date
            yield item

items中存取数据

import scrapy        
class HupuItem(scrapy.Item):
    title = scrapy.Field()
    author = scrapy.Field()
    ti_date = scrapy.Field()

通过selector获取到对象后,仍然可以继续对其使用xpath,css,等选择器继续选择。
result_list = response.selector.css('.for-list li')获取到result_list一个大的对象
title = index.css('.truetit::text').extract_first()继续对其使用css选择器并获取获取到的第一个数据
ti_date = index.css('.author.box').xpath('./a[2]/text()').extract_first()对其联合使用css选择器和xpath选择器
result = response.css('.author.box').xpath('./a[2]/text()').re('(.?)-.?-')对其联合使用xpath,css及正则选择器

5爬取有妖气网站(post请求)

5.1爬取数据

import json
import re    
import scrapy
from u17.items import U17Item        
class ComicSpider(scrapy.Spider):
    name = 'comic'
    allowed_domains = ['www.u17.com']
    start_urls = ['http://www.u17.com/']        
    def start_requests(self):
        headers = {
            'Referer': 'http://www.u17.com/comic/ajax.php?mod=comic_list&act=comic_list_new_fun&a=get_comic_list',
            'User-Agent': "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
            'Host': 'www.u17.com',
            'Accept': 'application/json, text/javascript, */*;',  # headers中requests headers中的accept数据
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6,ja;q=0.4,zh-TW;q=0.2,mt;q=0.2',
            'Connection': 'keep-alive',
            'X-Requested-With': 'XMLHttpRequest',
        }
        url = 'http://www.u17.com/comic/ajax.php?mod=comic_list&act=comic_list_new_fun&a=get_comic_list'
        data = {'data[group_id]': 'no', 'data[theme_id]': 'no', 'data[is_vip]': 'no', 'data[accredit]': 'no',
                     'data[color]': 'no', 'data[comic_type]': 'no', 'data[series_status]': '1', 'data[order]': '1',
                     'data[page_num]': '1', 'data[read_mode]': 'no'
                     }
        for page in range(5):
            data['data[page_num]'] = str(page)
            print(page)
            yield scrapy.FormRequest(url=url,
                                 headers=headers,
                                 method='POST',
                                 formdata=data,
                                 callback=self.parse,
                                 )    
    def parse(self, response):
        result=json.loads(response.text)
        result_list = result['comic_list']
        pattern = re.compile('<font.*?>(.*?)<.*?', re.S)
        for item in result_list:
            u17_item = U17Item()
            u17_item['comic_id'] = item['comic_id']
            u17_item['name'] = item['name']
            u17_item['cover'] = item['cover']
            u17_item['category'] = re.findall(pattern, item['line2'])[0]
            yield u17_item

注意:在循环提交请求的网页数据时;需将Request改为FormRequest;method改为POST
items中保存数据

import scrapy       
class U17Item(scrapy.Item):
    comic_id = scrapy.Field()
    name = scrapy.Field()
    cover = scrapy.Field()
    category = scrapy.Field()

该文件中保存数据的字段必须与spider文件中给对象添加属性的字段保持一致。
然后在settings文件中修改ROBOTSTXT_OBEY为False;添加编码方式FEED_EXPORT_ENCODING = 'utf-8'。

5.2保存数据

数据保存在管道(pipelines)中进行

5.2.1mysql中保存数据

import pymysql
import pymongo    
from scrapy import Request
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline
class U17MysqlPipeline(object):
    def __init__(self, host, port, username, password, database):
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.database = database    
    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            host=crawler.settings.get('MYSQL_HOST'),
            port=crawler.settings.get('MYSQL_PORT'),
            database=crawler.settings.get('MYSQL_DATABASE'),
            username=crawler.settings.get('MYSQL_USERNAME'),
            password=crawler.settings.get('MYSQL_PASSWORD'),
        )    
    def open_spider(self, spider):
        self.db = pymysql.connect(self.host, self.username, 
              self.password, self.database, charset='utf8',
                                  port=self.port)
        self.cursor = self.db.cursor()        
    def close_spider(self, spider):
        self.db.close()    
    def process_item(self, item, spider):
        sql = 'insert into manhua (comic_id, name, cover, category) 
            values (%s,%s,%s,%s)'
        self.cursor.execute(sql, (item['comic_id'], item['name'], 
            item['cover'], item['category']))
        self.db.commit()
        return item

5.2.2mongodb中保存数据

class U17MongoPipeline(object):
    def __init__(self, uri, database):
        self.uri = uri
        self.database = database    
    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            uri=crawler.settings.get('MONGO_URI'),
            database=crawler.settings.get('MONGO_DB'),
        )    
    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.uri)
        self.db = self.client[self.database]        
    def close_spider(self, spider):
        self.client.close()        
    def process_item(self, item, spider):
        self.db['manhua'].insert(dict(item))
        return item

5.2.3下载图片

class U17ImagePipeline(ImagesPipeline):
    # 准备图片文件名
    def file_path(self, request, response=None, info=None):
        url = request.url
        file_name = url.split('/')[-1]
        return file_name
    # 判断图片是否下载成功,丢弃不成功的
    def item_completed(self, results, item, info):
        image_paths = [x['path'] for ok, x in results if ok]
        if not image_paths:
            raise DropItem('Image Downloaded Failed')
        return item    
    # 指明图片下载链接,并包装成request对象
    def get_media_requests(self, item, info):
        yield Request(item['cover'])

5.2.4保存路径的配置

将上面定义的三个保存数据的类添加到settings中的ITEM_PIPELINES中(68行处)

ITEM_PIPELINES = {
# 前面是管道,后面是优先级,数值越小,优先级越高
'u17.pipelines.U17MysqlPipeline': 300,
'u17.pipelines.U17MongoPipeline': 320,
'u17.pipelines.U17ImagePipeline': 340,
}

'u17.pipelines.U17MysqlPipeline': 300, 前面是管道,后面是优先级,数值越小,优先级越高。将上面定义的保存数据的类添加到此处,运行spider文件,则会自动保存文件到对应的路径;当不需要保存到某个数据库时,在此处注释对应的方法就可以。
然后在最末行添加下面语句
在添加图片路径前,需要先在工程目录下创建images文件夹

 # 配置图片目录
 IMAGES_STORE = './images'      
 # mysql 设置
 MYSQL_HOST = '127.0.0.1'
 MYSQL_PORT = 3306
 MYSQL_USERNAME = 'root'
 MYSQL_PASSWORD = '123456'
 MYSQL_DATABASE = 'u17'      
 # MONGO 配置
 MONGO_URI = 'mongodb://127.0.0.1:27017'
 MONGO_DB = 'u17'
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 本主题主要是scrapy入门,包含内容如下:  1. Scrapy框架环境搭建;  2. 理解scrapy框架结...
    杨强AT南京阅读 1,319评论 0 10
  • scrapy框架Scrapy是用纯Python实现一个为了爬取网站数据、提取结构性数据而编写的应用框架,用途非常广...
    糖炒栗子_01c5阅读 2,888评论 0 2
  • 我一定会好起来,我一定要坚强,我必须坚强,我必须好起来!因为我非常爱我也非常爱我的家人!
    随心的爱阅读 292评论 5 1
  • 我喜欢你啊! 超级超级超级喜欢你! 好像年纪越大,越是说不出这种话了。喜欢的人,也越来越难碰到。 遥想多年前我还早...
    追星星的许茶茶阅读 204评论 0 0
  • 好久没写感恩日记了,这几天过得太水逆了,昏天暗地的日子,走过那段时间,真的会更加珍惜现在拥有的。 1、感恩小鱼儿和...
    快快妈妈育儿说阅读 142评论 0 1