scrapy 教程

在这里插入图片描述

中文文档:

scrapy 4 步:

  1. 新建项目:(scrapy startproject projectname):新建爬虫项目

  2. 创建爬虫:scrapy genspider spidername “http://www.xxx.cn/

  3. 明确目标:(编写items.py):明确想要抓取的目标

  4. 制作爬虫:(spiders/xxspider.py):制作爬虫开始爬取的网页

  5. 编写pipeline.py,处理spider返回的item数据。写Pipeline函数

  6. 编写settings.py,启动管道组件ITEM_PIPELINES={},以及其他相关设置USER_AGENT,DEFAULT_REQUEST_HEADERS

  7. 执行爬虫

     ```
         from scrapy import cmdline
         cmdline.execute(['scrapy','crawl','cib'])
     ```
    
创建爬虫
  • scrapy genspider spidername “http://www.xxx.cn/
    • genspider:表示生成一个爬虫(默认是scrapy.Spider类)
    • spidername:表示爬虫名(对应爬虫代码里的name参数)
    • http://www.xxx.cn/” :表示允许爬虫爬取的域范围
  • spidername.py
    • name= ‘’:爬虫的识别名称,唯一
    • allow_domains=[] :搜索的域名范围,爬虫的约束区域,规定爬虫只爬取这个域名下的网页,不存在的url会被忽略
    • start_urls=():爬取的url列表。爬虫从这里开始抓取数据,所以,第一次下载的数据将会从这些urls开始。其他子URL将会从这些起始URL中继承性生成
    • parse(self,response):解析的方法,每个初始URL完成下载后将被调用,调用的时候传入每一个URL传回的Response对象来作为唯一参数,主要作用如下:
    • 负责解析返回的网页数据(response.body),提取结构化数据(生成item)
    • 生成需要下一页的URL请求
    • start_requests(self):这个方法必须返回一个可迭代对象。该对象包含spider用于爬取(默认实现是使用start_urls的url)的第一个Request。当spider启动爬取并且为指定start_urls时,调用该方法
    • log(self,message[,level,component]):使用scrapy.log.msg()方法记录(log)message
执行爬虫
  • scrapy crawl spidername -o save_filename
    • crawl:表示启动一个scrapy爬虫
    • spidername:表示需要启动的爬虫名(对应爬虫代码里的name参数)
    • -0 :表示输出到文件
    • save_filename:表示保存文件的名称,,默认4种输出文件格式:json,jsonl,csv,xml
查看当前项目下的爬虫
  • scrapy list
pipeline的一些典型应用
  • 验证爬取的数据(检查item包含某些字段,比如说name)
  • 数据查重(并丢弃)
  • 将爬取结果保存到文件或者数据库中
    class SomethingPiple(object):
        def __init__(self):
            # 可选实现,做参数初始化,比如打开文件操作f.open('xxx','w',edcoding='utf-8')
            # doing something

        def open_spider(self,spider):
            # spider(Spider 对象) - 被关闭的spider
            # 可选实现,当spider被开启时,这个方法被调用。
            # 该方法和__init__方法功能基本相同。

        def process_item(self,item,spider):
            # item(Item对象) - 被爬取的item
            # spider (Spider对象) - 爬取该item的spider
            # 这个方法必须实现,每个item pipeline 组件都需要调用该方法
            # 这个方法必须返回一个Item对象,被丢弃的item将不会被之后的pipeline组件处理
            return item

        def close_spider(self,spider):
            # spider(Spider 对象) - 被关闭的spider
            # 可选实现,当spider被关闭时,这个方法被调用。
            # 比如关闭初始化打开的文件f.close()

启动Scrapy Shell:scrapy shell “www.baidu.com

  • response.headers:报头
  • response.body:报体
  • response.xpath()

Selectors选择器:

  • Selector有四个基本方法,最常用的是xpath:

    • xpath():传入xpath表达式,返回该表达式所对应的所有节点的selector list列表
      • XPath表达式的例子及对应含义:
        1. /html/head/title:选择文档中标签内的元素
        2. /html/head/title/text():选择文档中标签内的元素的文字
        3. //td:选择所有的元素
        4. //div[@class=“mine”]:选择所有具有class="mine"属性的div元素
    • extract():序列化该结点为Unicode字符串,并返回list
    • css():传入css表达式,返回该表达式所对应的所有节点的selector list列表,语法同BeautifulSoup4
    • re():根据传入的正则表达式对数据进行提取,返回Unicode字符串list列表

注意

  • xpath 返回的是一个列表
  • xpath.extract():将xpath对象转换成Unicode字符串
  • settings设置
    • HTTPERROR_ALLOWED_CODES = [403, 500, 404]
    • ROBOTSTXT_OBEY = False
    • 下载中间件:
        
        DOWNLOAD_DELAY = 2
        RANDOMIZE_DOWNLOAD_DELAY = True
        COOKIES_ENABLED = True
        
        DOWNLOADER_MIDDLEWARES = {
        'bank_info.middlewares.MyUserAgentMiddleware': 300,
        'bank_info.middlewares.BankInfoDownloaderMiddleware': 543, # 值越小优先级越高

        }
        ITEM_PIPELINES = {
        'bank_info.pipelines.BankInfoPipeline': 300, # 值越小优先级越高
        }
        

scrapy 进阶

  1. 翻页功能:scrapy.follow(next_page,callback=self.parse) 会自动拼接url和next_page
  2. 抽取response中满足xpath规则的链接:LinkExtractor(restrict_xpath=‘xxxx’), links = link.extract_links(response)
  3. 要防止scrapy被ban,主要有以下几个策略:
    • 动态设置user agent( 在middleware.py中随机选取user-agent,并把它赋值给request)
      1. 在settings开启UAMiddleware这个中间件:DOWNLOADER_MIDDLEWARES
      2.  import random
         class UAMiddleware(object):
             # 定义一个User-Agent的List
             ua_list = [
             'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 ',
             '(KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
             'Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)',
             'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)',
             'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
             'Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)',
             ]
        
             def process_request(self, request, spider): # 对request进行拦截
                 ua = random.choices(self.ua_list) # 使用random模块,随机在ua_list中选取User-Agent
                 request.headers['User-Agent'] = ua # 把选取出来的User-Agent赋给request
                 print(request.url) # 打印出request的url
                 print(request.headers['User-Agent']) # 打印出request的headers
        
             def process_response(self, request, response, spider): # 对response进行拦截
                 return response
             def process_exception(self, request, exception, spider): # 对process_request方法传出来的异常进行处理
                pass
        
    • 禁用cookies : COOKIES_ENABLED=False
    • 设置延迟下载 : DOWNLOAD_DELAY=2
    • 使用Google cache
    • 使用IP地址池(Tor project、VPN和代理IP)
    • 使用Crawlera
  4. scrapy中间件的分类:
    • scrapy的中间件理论上有三种(Schduler Middleware,Spider Middleware,Downloader Middleware),在应用上一般有以下两种:
      1. 爬虫中间件Spider Middleware:可以添加代码来处理发送给 Spiders 的response及spider产生的item和request.
        • 当蜘蛛传递请求和items给引擎的过程中,蜘蛛中间件可以对其进行处理(过滤出 URL 长度比 URLLENGTH_LIMIT 的 request。)
        • 当引擎传递响应给蜘蛛的过程中,蜘蛛中间件可以对响应进行过滤(例如过滤出所有失败(错误)的 HTTP response)
      2. 下载器中间件Downloader Middleware:主要功能在请求到网页后,页面被下载时进行一些处理.(反爬策略都是部署在下载中间件的)
        • 当引擎传递请求给下载器的过程中,下载中间件可以对请求进行处理 (例如增加http header信息,增加proxy信息等)
        • 在下载器完成http请求,传递响应给引擎的过程中, 下载中间件可以对响应进行处理(例如进行gzip的解压等)
        • 下载中间件三大函数:
          1. process_request(request, spider)——主要函数
            • process_request() 必须返回其中之一: 返回 None 、返回一个 Response 对象、返回一个 Request 对象或raise IgnoreRequest
            • 如果其返回 None: Scrapy将继续处理该request,执行其他的中间件的相应方法,直到合适的下载器处理函数(download handler)被调用, 该request被执行(其response被下载)
            • 如果其返回Response 对象: Scrapy将不会调用任何其他的process_request()或 process_exception()方法,或相应的下载函数。其将返回该response,已安装的中间件的 process_response() 方法则会在每个response返回时被调用
            • 如果其返回 Request对象 : Scrapy则会停止调用 process_request方法并重新调度返回的request,也就是把request重新返回,进入调度器重新入队列
            • 如果其返回raise IgnoreRequest异常 : 则安装的下载中间件的 process_exception()方法 会被调用。如果没有任何一个方法处理该异常, 则request的errback(Request.errback)方法会被调用。如果没有代码处理抛出的异常, 则该异常被忽略且不记录(不同于其他异常那样)
          2. process_response(request, response, spider)——主要函数
            • process_response() 必须返回以下之一:返回一个Response 对象、 返回一个Request 对象或raise IgnoreRequest 异常
            • 如果其返回一个 Response对象: (可以与传入的response相同,也可以是全新的对象), 该response会被在链中的其他中间件的 process_response() 方法处理
            • 如果其返回一个 Request对象: 则中间件链停止, 返回的request会被重新调度下载。处理类似于 process_request() 返回request所做的那样
            • 如果其抛出一个IgnoreRequest异常 :则调用request的errback(Request.errback)。
            • 如果没有代码处理抛出的异常,则该异常被忽略且不记录(不同于其他异常那样)
          3. process_exception(request, exception, spider)
            • 如果其返回 None : Scrapy将会继续处理该异常,接着调用已安装的其他中间件的 process_exception()方法,直到所有中间件都被调用完毕,则调用默认的异常处理
            • 如果其返回一个 Response 对象: 相当于异常被纠正了,则已安装的中间件链的 process_response()方法被调用。Scrapy将不会调用任何其他中间件的 process_exception()方法
            • 如果其返回一个 Request 对象: 则返回的request将会被重新调用下载。这将停止中间件的 process_exception() 方法执行,就如返回一个response的那样
其他内置的downloader middleware
itemvalue
DefaultHeadersMiddleware将所有request的头设置为默认模式
DownloadTimeoutMiddleware设置request的timeout
HttpAuthMiddleware对来自特定spider的request授权
HttpCacheMiddleware给request&response设置缓存策略
HttpProxyMiddleware给所有request设置http代理
RedirectMiddleware处理request的重定向
MetaRefreshMiddleware根据meta-refresh html tag处理重定向
RetryMiddleware失败重试策略
RobotsTxtMiddlewarerobots封禁处理
UserAgentMiddleware支持user agent重写
  1. 代理
# *-* coding:utf-8 *-*
import requests
from bs4 import BeautifulSoup
import lxml
from multiprocessing import Process, Queue
import random
import json
import time
import requests


class Proxies(object):
    """docstring for Proxies"""

    def __init__(self, page=3):
        self.proxies = []
        self.verify_pro = []
        self.page = page
        self.headers = {
            'Accept': '*/*',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36',
            'Accept-Encoding': 'gzip, deflate, sdch',
            'Accept-Language': 'zh-CN,zh;q=0.8'
        }
        self.get_proxies()
        self.get_proxies_nn()

    def get_proxies(self):
        page = random.randint(1, 10)
        page_stop = page + self.page
        while page < page_stop:
            url = 'http://www.xicidaili.com/nt/%d' % page
            html = requests.get(url, headers=self.headers).content
            soup = BeautifulSoup(html, 'lxml')
            ip_list = soup.find(id='ip_list')
            for odd in ip_list.find_all(class_='odd'):
                protocol = odd.find_all('td')[5].get_text().lower() + '://'
                self.proxies.append(protocol + ':'.join([x.get_text() for x in odd.find_all('td')[1:3]]))
            page += 1

    def get_proxies_nn(self):
        page = random.randint(1, 10)
        page_stop = page + self.page
        while page < page_stop:
            url = 'http://www.xicidaili.com/nn/%d' % page
            html = requests.get(url, headers=self.headers).content
            soup = BeautifulSoup(html, 'lxml')
            ip_list = soup.find(id='ip_list')
            for odd in ip_list.find_all(class_='odd'):
                protocol = odd.find_all('td')[5].get_text().lower() + '://'
                self.proxies.append(protocol + ':'.join([x.get_text() for x in odd.find_all('td')[1:3]]))
            page += 1

def verify_proxies(self):
    # 没验证的代理
    old_queue = Queue()
    # 验证后的代理
    new_queue = Queue()
    print('verify proxy........')
    works = []
    for _ in range(15):
        works.append(Process(target=self.verify_one_proxy, args=(old_queue, new_queue)))
    for work in works:
        work.start()
    for proxy in self.proxies:
        old_queue.put(proxy)
    for work in works:
        old_queue.put(0)
    for work in works:
        work.join()
    self.proxies = []
    while 1:
        try:
            self.proxies.append(new_queue.get(timeout=1))
        except:
            break
    print('verify_proxies done!')

def verify_one_proxy(self, old_queue, new_queue):
    while 1:
        proxy = old_queue.get()
        if proxy == 0: break
        protocol = 'https' if 'https' in proxy else 'http'
        proxies = {protocol: proxy}
        try:
            if requests.get('http://www.baidu.com', proxies=proxies, timeout=2).status_code == 200:
                print('success %s' % proxy)
                new_queue.put(proxy)
        except:
            print('fail %s' % proxy)


if __name__ == '__main__':
    a = Proxies()
    a.verify_proxies()
    print(a.proxies)
    proxie = a.proxies
    with open('proxies.txt', 'w') as f:
        for proxy in proxie:
            f.write(proxy + '\n')
  • 修改settings文件
    DOWNLOADER_MIDDLEWARES = {
        'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware':None,
        'myproxies.middlewares.ProxyMiddleWare':125,
        'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware':None
    }


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值