Scrapy的Request和Response

上节课我们学习了中间件,知道了怎么通过中间件执行反反爬策略。本节课主要介绍Scrapy框架的request对象和response对象

通常,Request对象在爬虫程序中生成并传递到系统,直到它们到达下载程序,后者执行请求并返回一个Response对象,该对象返回到发出请求的爬虫程序

Request类和Response类都有一些子类,子类用来添加基类中不必要的功能。这些在下面的请求子类和响应子类中描述

Request对象

一个Request对象表示一个HTTP请求,它通常是在爬虫中生成,并由下载器执行,从而返回Response

基础参数 :

url——请求的url

callback——请求回来的reseponse处理函数,也叫回调函数

meta——用来在“页面”之间传递数据

  • meta是一个dict,主要用来在解析函数之间传递值
  • 比如:在parse() 给item某些字段提取了值,并且提取出了一个新的URL,item另外一些字段需要在这个新的URL的response里面提取,为此定义一个parse_item()解析函数用于处理这个response。在用request发送这个新的URL请求的时候,使用parse_item()作为回调函数,并使用meta传递原来已经提取的item字段给parse_item()里的response
  • Request对象接受一个meta参数,一个字典对象,同时Response对象有一个meta属性可以取到相应request传过来的meta
  • 一旦此参数被设置, 通过参数传递的字典将会被浅拷贝

headers——页面的headers数据

cookies——设置页面的cookies

基础高级参数

encoding——请求的转换编码

priority——链接优先级

  • 优先级越高,越优先爬取,但不可以序列化
  • 序列化 (Serialization):将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象

dont_filter——强制不过滤 
scrapy会对request的URL去重,加上dont_filter则告诉它这个URL不参与去重

errback——错误回掉 
errback更适合用于检查记录请求产生的错误,但是不适合请求的重试

Request对象方法

copy():复制一个一模一样的对象 
replace():对对象参数进行替换

Request.meta 一些特殊的keys

  • dont_redirect:如果 Request.meta 包含 dont_redirect 键,则该request将会被RedirectMiddleware忽略
  • dont_retry:如果 Request.meta 包含 dont_retry 键, 该request将会被RetryMiddleware忽略
  • handle_httpstatus_list:Request.meta 中的 handle_httpstatus_list 键可以用来指定每个request所允许的response code
  • handle_httpstatus_all:handle_httpstatus_all为True ,可以允许请求的任何响应代码
  • dont_merge_cookies:Request.meta 中的dont_merge_cookies设为TRUE,可以避免与现有cookie合并
  • cookiejar:Scrapy通过使用 Request.meta中的cookiejar 来支持单spider追踪多cookie session。 默认情况下其使用一个cookie jar(session),不过可以传递一个标示符来使用多个
  • dont_cache:可以避免使用dont_cache元键等于True缓存每个策略的响应
  • redirect_urls:通过该中间件的(被重定向的)request的url可以通过 Request.meta 的 redirect_urls 键找到
  • bindaddress:用于执行请求的传出IP地址的IP
  • dont_obey_robotstxt:如果Request.meta将dont_obey_robotstxt键设置为True,则即使启用ROBOTSTXT_OBEY,RobotsTxtMiddleware也会忽略该请求
  • download_timeout:下载器在超时之前等待的时间(以秒为单位)
  • download_maxsize:爬取URL的最大长度
  • download_latency:自请求已经开始,即通过网络发送的HTTP消息,用于获取响应的时间量 
    该元密钥仅在下载响应时才可用。虽然大多数其他元键用于控制Scrapy行为,但是这个应用程序应该是只读的
  • download_fail_on_dataloss:是否在故障响应失败
  • proxy:可以将代理每个请求设置为像http:// some_proxy_server:port这样的值
  • ftp_user :用于FTP连接的用户名
  • ftp_password :用于FTP连接的密码
  • referrer_policy:为每个请求设置referrer_policy
  • max_retry_times:用于每个请求的重试次数。初始化时,max_retry_times元键比RETRY_TIMES设置更高优先级

Response对象

基础参数

url——请求的url 
body——请求回来的html 
meta——用来在“页面”之间传递数据 
headers——页面的headers数据 
cookies——设置页面的cookies 
Request——发出这个response的request对象

Response对象方法

copy():同request 
replace():同request 
urljoin():由于将页面相对路径改为绝对路径 
follow():对相对路径进行自动补全

urljoin()实例:

  1. import scrapy
  2. class QuotesSpider(scrapy.Spider):
  3. name = "quotes"
  4. start_urls = [
  5. 'http://quotes.toscrape.com/page/1/',
  6. ]
  7. def parse(self, response):
  8. #使用css选择器,提取出三个元素的目录的SelectorList
  9. for quote in response.css('div.quote'):
  10. yield {
  11. #使用css选择器,提取出text元素,并把它转换成字符串
  12. 'text': quote.css('span.text::text').extract_first(),
  13. #使用css选择器,提取出author元素,并把它转换成字符串
  14. 'author': quote.css('small.author::text').extract_first(),
  15. #使用css选择器,提取出tags元素,并把它转换成List
  16. 'tags': quote.css('div.tags a.tag::text').extract(),
  17. }
  18. #使用css选择器,提取出href元素,并把它转换成字符串
  19. next_page = response.css('li.next a::attr(href)').extract_first()#取出相对路径
  20. if next_page is not None:
  21. next_page = response.urljoin(next_page) #页面相对路径改为绝对路径
  22. yield scrapy.Request(next_page, callback=self.parse)

follow()实例:

  1. import scrapy
  2. class QuotesSpider(scrapy.Spider):
  3. name = "quotes"
  4. start_urls = [
  5. 'http://quotes.toscrape.com/page/1/',
  6. ]
  7. def parse(self, response):
  8. for quote in response.css('div.quote'):
  9. yield {
  10. 'text': quote.css('span.text::text').extract_first(),
  11. 'author': quote.css('span small::text').extract_first(),
  12. 'tags': quote.css('div.tags a.tag::text').extract(),
  13. }
  14. next_page = response.css('li.next a::attr(href)').extract_first()
  15. if next_page is not None:
  16. yield response.follow(next_page, callback=self.parse) #返回一个请求实例来跟踪一个链接url

Request、Response实例演示

本节课演示使用的依旧是上节课的58同城(city58)的例子 : 
city58_test.py:本例中演示了response的follow函数中相对路径转化为绝对路径,并且比较了request中各个参数的异同

  1.  
    # -*- coding: utf-8 -*-
  2.  
    import scrapy
  3.  
    from pyquery import PyQuery
  4.  
    from ..items import City58Item
  5.  
     
  6.  
    from scrapy.http import Request
  7.  
     
  8.  
     
  9.  
    class City58TestSpider(scrapy.Spider):
  10.  
    name = 'city58_test'
  11.  
    allowed_domains = ['58.com']
  12.  
    start_urls = ['http://bj.58.com/chuzu/',
  13.  
    # 'http://bj.58.com/chuzu/pn2/'
  14.  
    ]
  15.  
     
  16.  
    def parse(self, response):
  17.  
    jpy = PyQuery(response.text)
  18.  
    li_list = jpy('body > div.mainbox > div.main > div.content > div.listBox > ul > li').items()
  19.  
    for it in li_list:
  20.  
    a_tag = it('div.des > h2 > a')
  21.  
    item = City58Item()
  22.  
    item['name'] = a_tag.text()
  23.  
    item['url'] = a_tag.attr('href')
  24.  
    item['price'] = it('div.listliright > div.money > b').text()
  25.  
     
  26.  
    test_request = response.follow('/chuzu/pn2/', callback=self.parse) #使用response.follow方法把“/chuzu/pn2/”这个相对路径转换为绝对路径,并回调parse()函数
  27.  
    test_request2 = Request('http://bj.58.com/chuzu/pn3/',
  28.  
    callback=self.parse,
  29.  
    errback=self.error_back, #调用异常函数
  30.  
    cookies={}, #cookie设为空
  31.  
    headers={}, #headers设为空
  32.  
    priority=10
  33.  
    )
  34.  
    test_request3 = Request('http://58.com',
  35.  
    callback=self.parse,
  36.  
    errback=self.error_back, #调用异常函数
  37.  
    priority=10, #优先级设为10
  38.  
    meta={'dont_redirect': True} #不用重定向
  39.  
    )
  40.  
    test_request4 = Request('http://58.com',
  41.  
    callback=self.parse,
  42.  
    errback=self.error_back,
  43.  
    priority=10,
  44.  
    # meta={'dont_redirect': True}
  45.  
    dont_filter=True #对url不过滤
  46.  
    )
  47.  
    yield item
  48.  
    yield test_request
  49.  
    yield test_request2
  50.  
    yield test_request3
  51.  
    yield test_request4
  52.  
     
  53.  
    def error_back(self, e):
  54.  
    _ = self
  55.  
    print(e) #打印异常信息

实现58同城的翻页以及详情页的爬取

items.py:定义要爬取的内容

  1.  
    import scrapy
  2.  
     
  3.  
    class City58Item(scrapy.Item):
  4.  
    name = scrapy.Field()
  5.  
    price = scrapy.Field()
  6.  
    url = scrapy.Field()
  7.  
    introduce_item = scrapy.Field()
  8.  
    address = scrapy.Field()
  9.  
    phone_number = scrapy.Field()

city58_test.py:实现58同城的翻页以及详情页的爬取

  1.  
    # -*- coding: utf-8 -*-
  2.  
    import scrapy
  3.  
    from pyquery import PyQuery
  4.  
    from ..items import City58Item
  5.  
     
  6.  
    from scrapy.http import Request
  7.  
     
  8.  
     
  9.  
    class City58TestSpider(scrapy.Spider):
  10.  
    name = 'city58_test'
  11.  
    allowed_domains = ['58.com']
  12.  
    start_urls = ['http://bj.58.com/chuzu/']
  13.  
     
  14.  
    def parse(self, response):
  15.  
    jpy = PyQuery(response.text)
  16.  
    li_list = jpy('body > div.mainbox > div.main > div.content > div.listBox > ul > li').items()
  17.  
    for it in li_list:
  18.  
    a_tag = it('div.des > h2 > a')
  19.  
    item = City58Item()
  20.  
    item['name'] = a_tag.text()
  21.  
    item['url'] = a_tag.attr('href')
  22.  
    item['price'] = it('div.listliright > div.money > b').text()
  23.  
     
  24.  
    if item['url']: #判断url是否为空
  25.  
    yield Request(item['url'],
  26.  
    callback = self.detail_parse,
  27.  
    meta = {'item':item} , #使用meta参数,把item传给detail_parse()
  28.  
    priority = 10 , #优先级设为10
  29.  
    dont_filter=True #强制不过滤)
  30.  
    )
  31.  
     
  32.  
    url = jpy('#bottom_ad_li > div.pager > a.next').attr('href') #提取翻页链接
  33.  
    test_request = Request(url,
  34.  
    callback=self.parse,
  35.  
    priority=10,
  36.  
    # meta={'dont_redirect': True}
  37.  
    dont_filter=True # 对url不过滤
  38.  
    )
  39.  
    yield test_request #实现翻页
  40.  
     
  41.  
    def detail_parse(self,response):
  42.  
    jpy = PyQuery(response.text)
  43.  
    item = response.meta['item'] #接收item
  44.  
    item['introduce_item'] = jpy('body > div.main-wrap > div.house-detail-desc > div.main-detail-info.fl > div.house-word-introduce.f16.c_555 > ul > li:nth-child(1) > span.a2').text() #提取房屋亮点
  45.  
    item['address'] = jpy('body > div.main-wrap > div.house-basic-info > div.house-basic-right.fr > div.house-basic-desc > div.house-desc-item.fl.c_333 > ul > li:nth-child(6) > span.dz').text() #房屋详情地址
  46.  
    item['phone_number'] = jpy('body > div.main-wrap > div.house-basic-info > div.house-basic-right.fr > div.house-fraud-tip > div.house-chat-phone > span').text() #电话号码
  47.  
    return item

pipeline.py :与以前的例子相同,写入文件

  1.  
    import json
  2.  
     
  3.  
    class City58Pipeline(object):
  4.  
     
  5.  
    def open_spider(self,spider):
  6.  
    self.file = open('58_chuzu.txt', 'w' , encoding='utf8')
  7.  
    print('打开文件了')
  8.  
     
  9.  
    def process_item(self, item, spider):
  10.  
    line = '{}\n'.format(json.dumps(dict(item),ensure_ascii = False))
  11.  
    self.file.write(line)
  12.  
    return item
  13.  
     
  14.  
    def close_spider(self, spider):
  15.  
    self.file.close()
  16.  
    print('关闭文件了')

补充资料

使用FormRequest.from_response()方法模拟用户登录:

FormRequest类扩展了基本请求,具有处理HTML表单的功能。它使用lxml.html表单从表单数据预先填充表单域从响应对象

除了标准的Request方法之外,FormRequest对象还支持以下类方法:

classmethod from_response(response[, formname=None, formid=None, formnumber=0, formdata=None, formxpath=None, formcss=None, clickdata=None, dont_click=False, ...])

返回一个新的FormRequest对象,其表单字段值预先填充在给定响应中包含的HTML <form>元素中

该policy是默认情况下自动模拟任何可以点击的表单控件,如 < input type =“submit” >。即使这是非常方便的,通常是期望的行为,有时它可能会导致难以调试的问题。例如,使用javascript填充和/或提交的表单时,默认的from_response()行为可能不是最合适的。要禁用此行为,您可以将dont_click参数设置为True。另外,如果要更改点击的控件(而不是禁用它),还可以使用clickdata参数

  1.  
    import scrapy
  2.  
     
  3.  
    class LoginSpider(scrapy.Spider):
  4.  
    name = 'example.com'
  5.  
    start_urls = ['http://www.example.com/users/login.php']
  6.  
     
  7.  
    def parse(self, response):
  8.  
    return scrapy.FormRequest.from_response(
  9.  
    response,
  10.  
    formdata={'username': 'john', 'password': 'secret'}, #预先填好的账号密码
  11.  
    callback=self.after_login
  12.  
    )
  13.  
     
  14.  
    def after_login(self, response):
  15.  
    # check login succeed before going on
  16.  
    if "authentication failed" in response.body:
  17.  
    self.logger.error("Login failed")
  18.  
    return

 

Scrapy的Request和Response的更多相关文章

  1. python的scrapy框架的使用 和xpath的使用 && scrapy中request和response的函数参数 && parse()函数运行机制

    这篇博客主要是讲一下scrapy框架的使用,对于糗事百科爬取数据并未去专门处理 最后爬取的数据保存为json格式 一.先说一下pyharm怎么去看一些函数在源码中的代码实现 按着ctrl然后点击函数就 ...

  2. Scrapy的Request和Response对象

    一.Request 发送一个请求,参数如下: url :request对象发送请求的url callback :在下载器下载完相应的数据后执行的回调函数 method :请求方法,默认为get hea ...

  3. Scrapy爬虫入门Request和Response(请求和响应)

    开发环境:Python 3.6.0 版本 (当前最新)Scrapy 1.3.2 版本 (当前最新) 请求和响应 Scrapy的Request和Response对象用于爬网网站. 通常,Request对 ...

  4. Scrapy中的Request和Response

    Request Request 部分源码: # 部分代码 class Request(object_ref): def __init__(self, url, callback=None, metho ...

  5. scrapy中的Request和Response对象

    前言: 如果框架中的组件比做成是人的各个器官的话,那个Request和Response就是血液,Item就是代谢产物 Request对象: 是用来描述一个HTTP请求,其构造参数有 url 请求的UR ...

  6. scrapy之Request对象

    我们在使用scrapy框架的时候,会经常疑惑,数据流是怎么样在各个组件中间传递的.最近经常用scrapy+selenium爬取淘宝,又因为今天周五心情好,本宝宝决定梳理一下这方面知识. scrapy中 ...

  7. Request 和 Response 原理

    * Request 和 Response 原理:     * request对象和response对象由服务器创建,我们只需要在service方法中使用这两个对象即可        * 继承体系结构: ...

  8. Request 、Response 与Server的使用

    纯属记录总结,以下图片都是来自 ASP.NET笔记之 Request .Response 与Server的使用 Request Response Server 关于Server.MapPath 方法看 ...

  9. request 和response

    当今web程序的开发技术真是百家争鸣,ASP.NET, PHP, JSP,Perl, AJAX 等等. 无论Web技术在未来如何发展,理解Web程序之间通信的基本协议相当重要, 因为它让我们理解了We ...

随机推荐

  1. k8s helm 安装etcd

    待续 helm install etcd bitnami/etcd \ --set statefulset.replicaCount=3 \ --set persistence.enabled=tru ...

  2. JPA之排序条件查询

    List<Monitoring> monitoringList = repository.findAll((root, query, cb) -> { List<Predica ...

  3. Summary: DOM modification techniques

    Modifying an existing element We covered various ways that you can modify aspects of an existing ele ...

  4. java面试一日一题:讲下mysql中的undolog

    问题:请讲下mysql中undo log的作用 分析:mysql中有很多日志,例,bin log undo log redo log,要弄清楚这些日志的作用,就要了解这些日志出现的背景及要解决的问题: ...

  5. 5-tcp套接字服务端编程

    import socket 1.创建套接字 sockfd= socket.socket(socket_family = AF_INIT,socket_type=SOCK_STREAM,proto) 功 ...

  6. 【ElasticSearch】索引重建

    ElasticSearch索引重建 ElasticSearch索引一旦建立,便不可修改索引字段类型(允许增加或者删除该字段) 例如从Integer类型修改为long类型,这是不被允许的,错误信息如下: ...

  7. 异步访问技术Ajax(XMLHttpRequest)

    目录 AJAX XMLHttpRequest Ajax向服务器发送请求 Ajax接收服务器响应 AJAX - onreadystatechange 事件 使用 Callback 函数 一次Ajax请求 ...

  8. UVA11054Gergovia的酒交易

    题意:       有n个村庄,每个村庄要么买酒要么买酒,负数是买酒,整数是买酒,题目保证所有的数字想加和为0,保证有解,然后每一个村庄往相邻的村庄运k坛酒的花费是k,问满足所有的村庄的最小花费是多少 ...

  9. 修改VScode底部状态栏颜色

    点击齿轮进入setting 搜索workbench.colorCustomizations,然后点击编辑setting.json 修改为你喜欢的颜色即可,我这里修改为蓝色 例子: "work ...

  10. 取消本地SVN文件夹与服务器的关联

    方法一. 1.新建文本文档,添加内容如下: Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Fold ...