网络爬虫系列笔记(4)——Scrapy爬虫

3 篇文章 0 订阅
1 篇文章 0 订阅
Scrapy爬虫

Scrapy
不是一个简单的函数功能库;而是 一个专业的网络爬虫框架
Scrapy 足以支持一般商业服务所需的爬虫能力:持续爬取、商业服务、高可靠性

scrapy库的安装:
pip install scrapy
scrapy -h
Available commands:
  bench         Run quick benchmark test
  commands
  fetch         Fetch a URL using the Scrapy downloader
  genspider     Generate new spider using pre-defined templates
  runspider     Run a self-contained spider (without creating a project)
  settings      Get settings values
  shell         Interactive scraping console
  startproject  Create new project
  version       Print Scrapy version
  view          Open URL in browser, as seen by Scrapy

  [ more ]      More commands available when run from project directory

Unit1、Scrapy爬虫框架

一、Scrapy爬虫框架结构

  • 爬虫框架
    • 爬虫框架是实现爬虫功能的一个软件结构和功能组件集合。
    • 是一个半成品,帮助实现专业网络爬虫。
  • “5+2”结构:                                  已有实现,不用编写   
      • ENGINE            引擎
        • 控制所有模块之间的数据流
        • 根据条件触发事件
      • SCHEDULER    调度器
        • 对所有爬取请求进行调度管理,排访问顺序
      • ITEM PIPELINES (出口) 用户编写(也叫配置),对提取的信息进行后处理
        • 以流水线来处理Spider产生的爬取项
        • 有一组操作顺序组成,类似流水线,每个操作是一个Item Pipeline类型
        • 可能操作包括:清理、检验、查重爬取项的HTML数据、将数据储存到数据库
      • SPIDERS            (入口)  用户编写(也叫配置),提供初始URL链接,并解析所得网页内容,再提供链接
        • 解析Downloader返回的响应(Response)
        • 产生爬取项(scraped item)
        • 产生额外的爬取请求(Request)
      • DOWNLOADER    下载页面
      • Downloader Middlewares    (中间件)
        • 目的:实施Engine、Scheduler、Downloader之间进行用户可配置的控制
        • 功能:修改、丢弃、新增请求或响应(拦截)
      • Spider Middleware      (中间件)
        • 目的:对请求和爬取项再处理
        • 功能:修改、丢弃、新增请求或爬取项(拦截)





二、Requests  vs. Scrapy

  • 相同点:
    • 都可进行页面请求和爬取,是Python爬虫的两个重要技术路线。
    • 两都好用,文档丰富,入门简单。
    • 都么有处理js、提交表单、应对验证码等功能(可扩展)
  • 不同:

requests
Scrapy
页面级  网站级
功能库 框架
并发性不足,性能差 并发性好,性能较强(基于异步结构设计,有时太快会被反爬虫发现)
重点在于页面下载  重点在于爬虫框架
定制灵活 一般定制灵活,深度定制困难
上手十分简单 人门稍微难

三、Scrapy爬虫的常用命令

Scrapy命令行   (建立爬虫,运行爬虫)
Scrapy 是为持续运行设计的专业爬虫框架,提供操作的Scrapy命令行。
>scrapy <command> [options] [args]

命令行输入:
scrapy -h

常用命令:
startproject 创建一个新工程 scrapy startproject <name> [dir]
genspider 创建一个爬虫 scrapy genspider [options] <name> <domain>
settings 获得爬虫配置信息 scrapy settings [options]
crawl 运行一个爬虫 scrapy crawl <spider>
list 列出工程中所有爬虫 scrapy list
shell 启动URL调试命令行 scrapy shell [url]

Scrapy为什么采用命令行?
  • 命令行(而不是图形界面)更容易自动化,适合脚本控制。
  • 本质上,Scrapy是给程序员使用的,功能(而不是界面)更重要。




Unit2、Scrapy爬虫基本使用

产生步骤:
  1. 建立一个Scrapy爬虫工程
    • 命令行:D:\pycode>scrapy startproject python123demo
      • 生成工程目录:
        • Python123demo/------>外层目录
          • scrapy.cfg  ------>部署Scrapy爬虫的配置文件,服务器
          • Python123demo/-->Scrapy框架的用户自定义python代码
            • __init__.py-->初始化脚本
            • items.py  -->Items代码模板(继承类)
            • middlewares.py  -->Middlewares代码模板(继承类)
            • pipelines.py  -->Pipelines代码模板(继承类)
            • settings.py --->Scrapy爬虫的配置文件
            • spiders/   ----->Spiders代码模板目录(继承类)
              • __init__.py  ----->初始文件,无需修改
              • __pycache__/--->缓存目录,无需修改
  2. 在工程中产生一个Scrapy爬虫,产生一个Spider模板
    • 命令行:D:\pycode>cd python123demo
      •    D:\pycode\python123demo>scrapy genspider demo python123.io #爬取域名
      •    Created spider 'demo' using template 'basic' in module:  python123demo.spiders.demo作用:生成demo.py
  3. 编写产生的Spider模板
    • 修改dome.py文件
  4. 运行爬虫,获取网页

start_urls = ['http://python123.io/ws/demo.html']

#等价方法,完整代码部分 :
def start_requests(self):
    urls = [
            'http://python123.io/ws/demo.html'
           ]
    for url in urls:
        yield scrapy.Request(url=url, callback=self.parse)#当Url数量很大时,可以很有效的节省资源

yield关键字
                    yield <-->生成器
  • 生成器:一个不断产生值的函数
  • 包含yield语句的函数是一个生成器
  • 生成器每次产生一个值(yield语句),函数被冻结,被唤醒后再产生一个值。

#生成器写法
def gen(n):
     for i in range(n):
          yield i**2
for i in gen(5):
    print(i,' ', end="")

#普通写法
def square(n):
     ls = [i**2 for i in range(n)]
     return ls
for i in square(5):
    print(i,' ', end="")

##当n=1M、10M、100M或更大?生成器的重要优势

为何要使用生成器?
  • 生成器相比一次列出所有内容的优势
    • 更节省储存空间
    • 响应更迅速
    • 使用更加灵活

Scrapy爬虫的使用步骤:
  1. 创建一个工程和Spider模板
  2. 编写Spider
  3. 编写Item Pipeline
  4. 优化配置策略

Scrapy爬虫的数据类型:
1、Request类 (class scrapy.http.Request())
  •      Request对象表示一个HTTP请求
  •      由Spider生成,Downloader执行

属性、方法 .url .method .headers .body .meta .copy()
说明 对应URL 对应请求方法.'GET''POST'
字典类型请求 头
头部自定义
字符串类型请求内容 用户添加的扩展信息,Scrapy内部传递信息 复制该请求

2、Response类 (class scrapy.http.Request())
  •  Request对象表示一个HTTP响应
  •  由Downloader生成,Spider执行
属性和方法:
.url .status .headers .body .flags .request .copy(0
对应URL HTTP状态码,默认200 头部 内容 一组标记 对应Request对象 复制该响应


3、Item类 (class scrapy.item.Item())
  • Item对象表示一个从HTML页面中提取的信息内容。
  • 由Spider生成,由Item Pipeline处理。
  • Item类似字典类型,可以按照字典类型操作。

Scrapy爬虫提取信息的方法:
     Beautiful Soup     lxml     re     XPath Selector     CSS Selector

Xpath Selector:
举例
##<div id="test1">大家好!</div>
data = response.xpath('//div[@id="test1"]/text()').extract()[0]

##<div id="test3">我左青龙,<span id="tiger">右白虎,<ul>上朱雀,<li>下玄武。</li></ul>老牛在当中,</span>龙头在胸口。<div>
data = response.xpath('//div[@id="test3"]')
info = data.xpath('string(.)').extract()[0]

      CSS Selector的基本使用:(由W3C组织维护并规范)
          <HTML>.css('a::attr(href)').extract()
                         a:标签名     href:标签属性
www.w3school.com.cn/cssref/css_selectors.asp     (参考链接)
.class .intro 选择 class="intro" 的所有元素。 1
::selection ::selection 选择被用户选取的元素部分。
element p 选择所有 <p> 元素。 1
element,element div,p 选择所有 <div> 元素和所有 <p> 元素。 1
element element div p 选择 <div> 元素内部的所有 <p> 元素。 1

spider中应用举例:
start_urls = ["http://bj.lianjia.com/ershoufang/pg1tt2/"]

def parse(self, response):
        # 获取当前页面的房屋列表
        #house_lis = response.css('.house-lst .info-panel')
        # 把结果输出到文件(在命令行中房屋标题会因为编码原因显示为乱码)
        with open("homelink.log", "wb") as f:
            ## 使用css selector进行操作
            #average_price = response.css(' .secondcon.fl li:nth-child(1)').css(' .botline a::text').extract_first()
            #f.write("Average Price: " + str(average_price) + "\r\n")
            #yesterday_count = response.css('.secondcon.fl li:last-child').css('.botline strong::text').extract_first()
            #f.write("Yesterday Count: " + str(yesterday_count) + "\r\n")
            #for house_li in house_lis:
            #    link = house_li.css('a::attr("href")').extract_first()            # 获取房屋的链接地址
            #    title = house_li.css('a::text').extract_first()                    # 获取房屋的标题
            #    price = house_li.css('.price .num::text').extract_first()          # 获取房屋的价格


Unit2、实例4,股票数据Scrapy爬虫

要求同实例3
Scrapy爬虫步骤:
  1. 创建一个工程和Spider模板
    • scrapy startproject BaiduStocks
    • cd BaiduStocks
    • scrapy genspider stocks baidu.com
    • 修改spiders/stocks.py文件
  2. 编写Spider
    • 配置stocks.py文件
    • 修改对返回页面的处理
    • 修改对新增URL爬取请求的处理
  3. 编写Item Pipeline
    • 配置pipelines.py文件
    • 定义对爬取项(Scrapy Item)的处理类
    • 配置Item_Pipelines选项(settings.py文件)
  4. 优化配置策略
    • 配置并发连接选项(settings.py文件)
      • CONCURRENT_REQUESTS     Downloader最大并发请求下载数量,默认32
      • CONCURRENT_ITEMS    Item Pipeline最大并发ITEM处理数量,默认100
      • CONCURRENT_REQUESTS_PER_DOMAIN     每个目标域名最大并发请求数量,默认8
      • CONCURRENT_REQUESTS_PER_IP     每个目标IP最大并发请求数量,默认0,非0有效
  5. 执行程序
    • scrapy crawl stocks

spider代码:
(stocks.py文件源代码)
# -*- coding: utf-8 -*-
import scrapy
import re


class StocksSpider(scrapy.Spider):
    name = "stocks"
    start_urls = ['http://quote.eastmoney.com/stocklist.html']

    def parse(self, response):
        for href in response.css('a::attr(href)').ectract():
            try:
                stock = re.findall(r'[s][hz]\d{6}', href)[0]
                url = 'https://gupiao.baidu.com/stock/' + stock + '.html'
                yield scrapy.Request(url, callback=self.parse_stock)
                #此处callback 给出处理该Url 所对应的函数
            except:
                continue

    def parse_stock(self, response):
        infoDict = {}
        stockInfo = response.css('.stock-bets')
        name = stockInfo.css('.bets-name').extract()[0]
        keyList = stockInfo.css('dt').extract()
        valueList = stockInfo.css('dd').extract()
        for i in range(len(keyList)):
            key = re.findall(r'>.*</dt>', keyList[i])[0][1:-5]
            try:
                val = re.findall(r'\d+\.?.*</dd>', valueList[i])[0][0:-5]
            except:
                val = '--'
        infoDict.update({'股票名称': re.findall('\s.*\(',name)[0].split()[0]+\
        re.findall('\>.*\<', name)[0][1:-1]})
        #使用yield,将结果封装成Item类,传给ItemPipeline
        yield infoDict

pipelines.py文件源代码:
# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html


class BaidustocksPipeline(object):
    def process_item(self, item, spider):
        return item

class BaidustocksInfoPipeline(object):
    #爬虫启动时Pipeline对应的方法
    def open_spider(self, spider):
        self.f = open('BaiduStockInfo.txt', 'w')

    #爬虫关闭时Pipeline对应的方法
    def close_spider(self, spider):
        self.f.close()

    #对每一个Item进行处理时对应的方法:主体函数
    def process_item(self, item, spider):
        try:
            line = str(dict(item)) + '\n'
            self.f.write(line)
        except:
            pass
        return item


settings.py文件中被修改的区域:

- # Configure item pipelines
- # See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
- ITEM_PIPELINES = {
-     'BaiduStocks.pipelines.BaidustocksInfoPipeline': 300,
- }



Unit3、扩展

表单提交、爬取周期、入库存储
requests-bs4-re          
scrapy                         +               PhantomJS

scrapyd-*          https://pypi.python.org

Scrapy 爬虫的应用展望
  • 普通价值:
    • 基于Linux,7*24,稳定输出
    • 商业级部署和应用(scrapyd-*)
    • 千万规模内URL爬取、内容分析和存储
  • 高阶价值:
    • 基于docker,虚拟化部署
    • 中间件扩展,增加调度和监控
    • 各种反爬虫对抗技术


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值