Python爬虫框架 scrapy 入门经典project 爬取校花网资源、批量下载图片

####一、安装scrapy
建议:最好在新的虚拟环境里面安装scrapy
注意:博主是在 Ubuntu18.04 + Python3.6 环境下进行开发的,若是遇到安装scrapy不成功请自行百度/谷歌解决php

pip install scrapy

顺便装上iPython 这样方便操做scrapy shellcss

pip install ipython

####二、scrapy入门讲解
先附上爬取原理图
这里写图片描述
(1)建立项目html

经过指令来进行建立的
scrapy startproject firstSpider(项目名称)

(2)项目目录结构python

firstSpider
	firstSpider
		spiders           爬虫目录(写代码位置)
			__init__.py   表示这是一个Python模块
			first.py      爬虫文件
		__init__.py
		items.py          定义数据结构地方
		middlewares.py    中间件
		pipelines.py      管道文件
		settings.py       项目配置文件
	scrapy.cfg
经过指令建立爬虫文件
			cd firstSpider/firstSpider
			scrapy genspider qiubai "www.qiushibaike.com"
			那么就会在firstSpider/firstSpider/spiders里面自动建立一个qiubai.py
		name: 爬虫的名字,启动的时候根据爬虫的名字启动项目
		allowed_domains:容许的域名,就是爬取的时候这个请求要不要发送,若是是该容许域名之下的url,就会发送,若是不是,则过滤掉这个请求,这是一个列表,能够写多个容许的域名
		start_urls:爬虫起始url,是一个列表,里面能够写多个,通常只写一个
		def parse(self, response): 这个函数很是重要,就是你之后写代码的地方,parse函数名是固定的,当收到下载数据的时候会自动的调用这个方法,该方法第二个参数为response,这是一个响应对象,从该对象中获取html字符串,而后解析之。【注】这个parse函数必须返回一个可迭代对象

(3)定制items.py,其实就是您的数据结构,格式很是简单,复制粘贴便可
(4)打印response对象,简单跑一把git

来到终端下:
cd firstSpider/firstSpider/spiders
scrapy crawl qiubai

根据response获取网页内容
response.text    字符串类型
response.body    二进制类型

(5)运行,直接经过命令导出json格式web

scrapy crawl qiubai -o qiubai.json
scrapy crawl qiubai -o qiubai.xml
scrapy crawl qiubai -o qiubai.csv

(6)scrapy shell 的使用shell

scrapy shell
	运行在终端的工具,用来调试scrapy
	简单使用
	# 注意不能在已近建立好的scrapy目录下操做,不然返回的response为 none
	(1)scrapy shell "http://www.xiaohuar.com/hua/"
		response对象
			属性
				text:字符串格式的html
				body:二进制格式的html
				url:所请求的url
				status:响应的状态码
			方法:
				xpath(): 根据xpath路径获取符合的路径全部selector对象(是scrapy本身封装的一个类的对象)的列表
				css(): 根据选择器获取符合选择器要求的全部selector对象的列表
				获取内容的时候要这么写
					#detail-list > li .header > a > div > .name::text
				获取属性的方法要这么写
					#detail-list > li .header > a > div > .name::attr("data-src")
				下面接着extract()便可  
				通常不使用这个,由于中间scrapy会将这个选择器给翻译成xpath再去解析
			selector对象
				xpath('./'): 从当前节点向下开始查找 
				css(): 和上面的response的方式同样
				extract(): 将对象转化为unicode字符串,供你的代码使用
				extract_first(): 理论上至关于上面的  
					name_list.extract()[0] == name_list.extract_first()
					但实际上,extract_first()要比extract()强大,若是xpath没有获取到内容,extract_first()会返回None
	(2)item对象
		官方的这个Item其实就是一个类字典的对象,或者你就能够叫作它就是一个字典,用的时候和字典的用法如出一辙
		将这个对象转化为字典
			pp = dict(p)

####三、实战-爬取校花网图片资源
一、settings.py文件的配置json

# 使用的请求ua
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0(Macintosh;IntelMacOSX10.6;rv:2.0.1)Gecko/20100101Firefox/4.0.1'

# 是否遵循国际爬虫条例,我的写的爬虫不须要遵循
# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# 设置的请求头
# Override the default request headers:
DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  # 'Accept-Language': 'en',
}

# Configure item pipelines
# See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
# 表示使用管道 这里300表示处理的优先级
# 你也能够本身再写一部分管道,而后设置优先级处理
ITEM_PIPELINES = {
   'huaproject.pipelines.HuaprojectPipeline': 300,
}
####剩余配置默认便可

二、items.py文件的处理数据结构

import scrapy


class HuaprojectItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    # 须要的数据如今这里制定好,由于在settings里面已近设置好了,因此能够和pipelines联系在一块处理数据
    # 图片连接
    image_url = scrapy.Field()
    # 名字
    name = scrapy.Field()
    # 大学
    school = scrapy.Field()
    # 喜欢数
    like = scrapy.Field()

三、关键爬虫文件xiaohua.py的处理app

import scrapy
# 导入数据结构类
from huaproject.items import HuaprojectItem

class XiaohuaSpider(scrapy.Spider):
    name = 'xiaohua'
    allowed_domains = ['www.xiaohuar.com']
    # 基础url
    url = 'http://www.xiaohuar.com/list-1-'
    # 爬取的起始页
    page = 0
    # 爬取的起始url
    start_urls = ['http://www.xiaohuar.com/hua/list-1-0.html']

    # 定义的方法,注意这个方法名不能修改,传入的参数也不能修改,不然会出错
    def parse(self, response):
        # print(100)
        # 解析全部校花,获取指定内容
        div_list = response.xpath('//div[@class="item masonry_brick"]')
        # print(div_list)
        # 遍历上面全部的div,找到指定的内容便可
        for div in div_list:
            # 建立item对象 就是咱们在items里面定义的类
            item = HuaprojectItem()
            image_url = div.xpath('./div[@class="item_t"]/div[@class="img"]/a/img/@src').extract_first()
            # 处理周半仙图片是以.php结尾的
            if image_url.endswith('.php'):
                image_url = image_url.replace('.php', '.jpg')

            # 拼接图片的全路径
            image_url = 'http://www.xiaohuar.com' + image_url

            name = div.xpath('./div[@class="item_t"]/div[@class="img"]/span[@class="price"]/text()').extract_first()
            school = div.xpath('./div[@class="item_t"]/div[@class="img"]/div[@class="btns"]/a/text()').extract_first()
            like = div.xpath('./div[contains(@class,"item_b")]//em[@class="bold"]/text()').extract_first()
            # 将上面提取的属性保存到对象中
            item['image_url'] = image_url
            item['name'] = name
            item['school'] = school
            item['like'] = like
            # 将该item对象返回
            yield item

        # url = 'http://www.xiaohuar.com/hua/list-1-'
        # page = 0
        # 当处理完第一页的时候,要接着发送请求,处理下一页
        self.page += 1
        if self.page <= 11:
            url = self.url + str(self.page) + '.html'
            # 再次的发送请求,而且指定回调处理函数进行处理对应的请求
            yield scrapy.Request(url=url, callback=self.parse)

四、pipelines.py文件的处理

import json
import os
import urllib.request

class HuaprojectPipeline(object):
    # 重写构造方法,在这打开文件
    def __init__(self):
        # 文件的打开写到这里,仅会执行一次
        self.fp = open('xiaohua.json', 'w', encoding='utf-8')
        
    def open_spider(self, spider):
        pass

    # 在这里处理每个item
    def process_item(self, item, spider):
        # 将这个对象转化为字典
        obj = dict(item)

        # 将图片下载到本地
        # 获取当前目录的绝对路径
        file_root_path = os.path.dirname(os.path.abspath(__file__))
        # 拼接须要保存的路径
        img_dir_path = os.path.join(file_root_path, 'spiders/images')
        # 判断这个目录是否已经存在,不存在就自动建立
        is_have_img_dir = os.path.exists(img_dir_path)
        if is_have_img_dir:
            pass
        else:
            os.mkdir(img_dir_path)
        # 获取图片后缀名
        suffix = os.path.splitext(obj['image_url'])[-1]
        # 拼接文件名
        filename = obj['like'] + '_' + obj['school'] + '_' +  obj['name'] + suffix
        # 将文件路径和文件名拼接出来文件的全路径
        filepath = os.path.join(img_dir_path, filename)
        # 下载图片
        urllib.request.urlretrieve(obj['image_url'], filepath)

        # 将obj转化为字符串
        string = json.dumps(obj, ensure_ascii=False)
        self.fp.write(string + '\n')
        return item

    # 重写这个方法,在关闭spider的时候将文件资源关闭
    def close_spider(self, spider):
        self.fp.close()

五、最后附上项目地址
git@gitee.com:aeasringnar/xiaohuaproject.git