介: Request类是一个http请求的类,对于爬虫而言是一个很重要的类。通常在Spider中创建这样的一个请求,在Downloader中执行这样的一个请求。同时也有一个子类FormRequest继承于它,用于post请求。
Request类是一个http请求的类,对于爬虫而言是一个很重要的类。通常在Spider中创建这样的一个请求,在Downloader中执行这样的一个请求。同时也有一个子类FormRequest继承于它,用于post请求。
在Spider中通常用法:
yield scrapy. Request (url='zarten.com' )
类属性和方法有:
url method headers body meta copy() replace([url, method, headers, body, cookies, meta, encoding, dont_filter, callback, errback]) Request class scrapy.http.
Request
(url[, callback, method='GET' , headers, body, cookies, meta, encoding='utf-8' , priority=0 , dont_filter=False , errback, flags])
url 请求的url
callback 回调函数,用于接收请求后的返回信息,若没指定,则默认为parse()函数
method http请求的方式,默认为GET请求,一般不需要指定。若需要POST请求,用FormRequest即可
headers 请求头信息,一般在settings中设置即可,也可在middlewares中设置
body str类型,为请求体,一般不需要设置(get和post其实都可以通过body来传递参数,不过一般不用)
cookies dict或list类型,请求的cookie dict方式(name和value的键值对):
cookies={ 'name1' : 'value1' , 'name2' : 'value2' }
list方式:
cookies=[ { 'name' : 'Zarten' , 'value' : 'my name is Zarten' , 'domain' : 'example.com' , 'path' : '/currency' } ]
encoding 请求的编码方式,默认为'utf-8'
priority int类型,指定请求的优先级,数字越大优先级越高,可以为负数,默认为0
dont_filter 默认为False,若设置为True,这次请求将不会过滤(不会加入到去重队列中),可以多次执行相同的请求
errback 抛出错误的回调函数,错误包括404,超时,DNS错误等,第一个参数为Twisted Failure实例
from scrapy.spidermiddlewares.httperror import HttpError from twisted.internet.error import DNSLookupError from twisted.internet.error import TimeoutError , TCPTimedOutError class ToScrapeCSSSpider (scrapy. Spider ): name="toscrape-css" # start_urls=[ # 'http://quotes.toscrape.com/', # ] start_urls=[ "http://www.httpbin.org/" , # HTTP 200 expected "http://www.httpbin.org/status/404" , # Not found error "http://www.httpbin.org/status/500" , # server issue "http://www.httpbin.org:12345/" , # non-responding host, timeout expected "http://www.httphttpbinbin.org/" , # DNS error expected ] def start_requests( self ): for u in self .start_urls: yield scrapy. Request (u, callback=self .parse_httpbin, errback=self .errback_httpbin, dont_filter=True ) def parse_httpbin( self , response): self .logger.info( 'Got successful response from {}' .format(response.url)) # do something useful here... def errback_httpbin( self , failure): # log all failures self .logger.info(repr(failure)) # in case you want to do something special for some errors, # you may need the failure's type: if failure.check( HttpError ): # these exceptions come from HttpError spider middleware # you can get the non-200 response response=failure.value.response self .logger.info( 'HttpError错误 on %s' , response.url) elif failure.check( DNSLookupError ): # this is the original request request=failure.request self .logger.info( 'DNSLookupError错误 on %s' , request.url) elif failure.check( TimeoutError , TCPTimedOutError ): request=failure.request self .logger.info( 'TimeoutError错误 on %s' , request.url)
flags list类型,一般不会用到,发送请求的标志,一般用于日志记录
meta 可用户自定义从Request到Response传递参数,这个参数一般也可在middlewares中处理
yield scrapy. Request (url='zarten.com' , meta={ 'name' : 'Zarten' })
在Response中:
my_name=response.meta[ 'name' ]
不过也有scrapy内置的特殊key,也非常有用,它们如下:
proxy 设置代理,一般在middlewares中设置
可以设置http或https代理
request.meta[ 'proxy' ]='https://' + 'ip:port'
downloadtimeout 设置请求超时等待时间(秒),通常在settings中设置DOWNLOADTIMEOUT,默认是180秒(3分钟)
maxretrytimes 最大重试次数(除去第一次下载),默认为2次,通常在settings中 RETRY_TIMES设置
dont_redirect 设为True后,Request将不会重定向
dont_retry 设为True后,对于http链接错误或超时的请求将不再重试请求
handlehttpstatuslist http返回码200-300之间都是成功的返回,超出这个范围的都是失败返回,scrapy默认是过滤了这些返回,不会接收这些错误的返回进行处理。不过可以自定义处理哪些错误返回:
yield scrapy. Request (url='https://httpbin.org/get/zarten' , meta={ 'handle_httpstatus_list' : [ 404 ]})
在parse函数中可以看到处理404错误:
def parse( self , response): print ( '返回信息为:' ,response.text)
handlehttpstatusall 设为True后,Response将接收处理任意状态码的返回信息
dontmergecookies scrapy会自动保存返回的cookies,用于它的下次请求,当我们指定了自定义cookies时,如果我们不需要合并返回的cookies而使用自己指定的cookies,可以设为True
cookiejar 可以在单个spider中追踪多个cookie,它不是粘性的,需要在每次请求时都带上
def start_requests( self ): urls=[ 'http://quotes.toscrape.com/page/1' , 'http://quotes.toscrape.com/page/3' , 'http://quotes.toscrape.com/page/5' , ] for i ,url in enumerate(urls): yield scrapy. Request (url=url, meta={ 'cookiejar' : i}) def parse( self , response): next_page_url=response.css( "li.next > a::attr(href)" ).extract_first() if next_page_url is not None : yield scrapy. Request (response.urljoin(next_page_url), meta={ 'cookiejar' : response.meta[ 'cookiejar' ]}, callback=self .parse_next) def parse_next( self , response): print ( 'cookiejar:' , response.meta[ 'cookiejar' ])
dont_cache 设为True后,不会缓存
redirect_urls 暂时还不清楚具体的作用,知道的小伙伴们欢迎在评论留言
bindaddress 绑定输出IP
dontobeyrobotstxt 设为True,不遵守robots协议,通常在settings中设置
downloadmaxsize 设置下载器最大下载的大小(字节),通常在settings中设置DOWNLOADMAXSIZE,默认为1073741824 (1024MB=1G),若不设置最大的下载限制,设为0
download_latency 只读属性,获取请求的响应时间(秒)
def start_requests( self ): headers={ 'user-agent' : 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36' } yield scrapy. Request (url='https://www.amazon.com' , headers=headers) def parse( self , response): print ( '响应时间为:' , response.meta[ 'download_latency' ])
downloadfailon_dataloss 很少用到,详情看这里
referrer_policy 设置Referrer Policy
FormRequest
FormRequest 类为Request的子类,用于POST请求
这个类新增了一个参数 formdata,其他参数与Request一样,详细可参考上面的讲述
yield scrapy. FormRequest (url="http://www.example.com/post/action" , formdata={ 'name' : 'Zarten' , 'age' : '27' }, callback=self .after_post)
点击“了解更多”看源代码,建议收藏
得十多年前,自己还是个高中生的时候,所谓的智能手机还完全没有普及,如果想在学校里面大量阅读电子书的话,基本上靠的就是有阅读 功能的MP3或者MP4了。而电子书的来源呢?在无法随时随地接触网络的情况下,有时靠的就是笨办法:将一些小说网站上的内容一页页的粘贴复制下来。而那些动辄几百章节的网络小说,靠这样的手工操作,确实让人非常头疼。那时候是多么希望有一个工具能帮我自动完成这些吃力的手工活啊!!!
好吧,言归正传,最近在研究怎么使用爬虫框架Scrapy。先说说想要学习Scrapy的初衷吧。
Scrapy是Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试(百度百科上的介绍)。
经过几天的学习,Scrapy的初步使用,首先需要了解的就是如下几个概念了:
所以,你需要做得就是写好上面提到的四个类,剩下的只要交给Scrapy框架就可以了。
可以先创建一个scrapy项目:
scrapy startproject getMyFavoritePages
文件spiderForShortPageMsg.py里面就是我们要写的 Spiders子类了。
举例:现在我想要将网站https://lobste.rs/中所有文章的标题和文章的地址抓取下来。
第一步:写一个继承自 Spiders的类
Scrapy框架会自动调用该类的方法parse(),在这里parse()最后调用了自定义的方法parse_lobste_com()来解析具体的html页面,并从中找到我想要的数据,然后保存于一个 Items的数据类对象当中。
不要被下面的这行代码吓到:
response.xpath("//div/div[2]/span[1]/a[@class='u-url']"
它就是之前提到的 Selectors。这就是用来定位你想要查找的html标签的方法。有俩种 Selectors, 分别是 XPath Selectors 和 CSS Selectors,上面都有用到。
这是我的Item数据类(即上面的pageItem)。
第二步:在Item Pipeline中定义你想要对数据类Item进行的所有操作。
现在想要的数据已经在Item对象当中了。考虑到自己的最终目的,最好的选择当然是把所有的数据都保存在数据库当中了。
而说到数据库的操作,就不得不提Django中的models类了,通过几步简单的设置,你可以直接调用Django中的models类,进而省去复杂了数据库操作,简直不要太省心了。谁用谁知道啊!!
代码写好,程序开始运行...
注意!只有当调度器中不存在任何request了,整个程序才会停止,(也就是说,对于下载失败的URL,Scrapy也会重新下载。)
制作 Scrapy 爬虫 一共需要4步:
Scrapy框架官方网址:http://doc.scrapy.org/en/latest
Scrapy中文维护站点:http://scrapy-chs.readthedocs.io/zh_CN/latest/index.html
安装后,只要在命令终端输入 scrapy,提示类似以下结果,代表已经安装成功
具体Scrapy安装流程参考:http://doc.scrapy.org/en/latest/intro/install.html#intro-install-platform-notes 里面有各个平台的安装方法
scrapy startproject mySpider
下面来简单介绍一下各个主要文件的作用:
scrapy.cfg :项目的配置文件
mySpider/ :项目的Python模块,将会从这里引用代码
mySpider/items.py :项目的目标文件
mySpider/pipelines.py :项目的管道文件
mySpider/settings.py :项目的设置文件
mySpider/spiders/ :存储爬虫代码目录
我们打算抓取:http://www.itcast.cn/channel/teacher.shtml 网站里的所有讲师的姓名、职称和个人信息。
import scrapy
class ItcastItem(scrapy.Item):
name=scrapy.Field()
level=scrapy.Field()
info=scrapy.Field()
爬虫功能要分两步:
scrapy genspider itcast "itcast.cn"
import scrapy
class ItcastSpider(scrapy.Spider):
name="itcast"
allowed_domains=["itcast.cn"]
start_urls=(
'http://www.itcast.cn/',
)
def parse(self, response):
pass
其实也可以由我们自行创建itcast.py并编写上面的代码,只不过使用命令可以免去编写固定代码的麻烦
要建立一个Spider, 你必须用scrapy.Spider类创建一个子类,并确定了三个强制的属性 和 一个方法。
将start_urls的值修改为需要爬取的第一个url
start_urls=("http://www.itcast.cn/channel/teacher.shtml",)
修改parse()方法
def parse(self, response):
with open("teacher.html", "w") as f:
f.write(response.text)
然后运行一下看看,在mySpider目录下执行:
scrapy crawl itcast
是的,就是 itcast,看上面代码,它是 ItcastSpider 类的 name 属性,也就是使用 scrapy genspider命令的爬虫名。
一个Scrapy爬虫项目里,可以存在多个爬虫。各个爬虫在执行时,就是按照 name 属性来区分。
运行之后,如果打印的日志出现 [scrapy] INFO: Spider closed (finished),代表执行完成。 之后当前文件夹中就出现了一个 teacher.html 文件,里面就是我们刚刚要爬取的网页的全部源代码信息。
# 注意,Python2.x默认编码环境是ASCII,当和取回的数据编码格式不一致时,可能会造成乱码;
# 我们可以指定保存内容的编码格式,一般情况下,我们可以在代码最上方添加:
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
# 这三行代码是Python2.x里解决中文编码的万能钥匙,经过这么多年的吐槽后Python3学乖了,默认编码是Unicode了...(祝大家早日拥抱Python3)
<div class="li_txt">
<h3> xxx </h3>
<h4> xxxxx </h4>
<p> xxxxxxxx </p>
是不是一目了然?直接上XPath开始提取数据吧。
from mySpider.items import ItcastItem
from mySpider.items import ItcastItem
def parse(self, response):
#open("teacher.html","wb").write(response.body).close()
# 存放老师信息的集合
items=[]
for each in response.xpath("//div[@class='li_txt']"):
# 将我们得到的数据封装到一个 `ItcastItem` 对象
item=ItcastItem()
#extract()方法返回的都是unicode字符串
name=each.xpath("h3/text()").extract()
title=each.xpath("h4/text()").extract()
info=each.xpath("p/text()").extract()
#xpath返回的是包含一个元素的列表
item['name']=name[0]
item['title']=title[0]
item['info']=info[0]
items.append(item)
# 直接返回最后数据
return items
# json格式,默认为Unicode编码
scrapy crawl itcast -o teachers.json
# json lines格式,默认为Unicode编码
scrapy crawl itcast -o teachers.jsonl
# csv 逗号表达式,可用Excel打开
scrapy crawl itcast -o teachers.csv
# xml格式
scrapy crawl itcast -o teachers.xml
*请认真填写需求信息,我们会在24小时内与您取得联系。