Scrapy 使用
1、必须创建一个新的Scrapy项目。 进入您打算存储代码的目录中,运行下列命令 创建 Scrapy 项目
# 常用的三个命令
scrapy startproject mzt_crawl # 生成项目
scrapy genspider mzt example.com # 会创建一个 mzt.py
scrapy crawl test_spider # .cfg 目录执行,启动爬虫 代码写好后执行
也可以在 .cfg 同目录下创建 main.py
from scrapy import cmdline
cmdline.execute(['scrapy','crawl','mzt']) # spider和crawl是固定格式
该命令会创建包含下列内容的test_spider
目录
test_spider
test_spider
scrapy.cfg # 项目的配置文件
__init__.py # 该项目的python模块
items.py # 项目中的item文件
middlewares.py # 项目中的pipelines文件
pipelines.py # 项目的设置文件
settings.py # 放置spider代码的目录.
mzt.py # 爬虫文件
scrapy.Spider
scrapy 的爬虫文件
import scrapy
from ..items import MztCrawlItem
class MztSpider(scrapy.Spider):
name = 'mzt'
# allowed_domains = ['www.laotuzi.com/meizitu/']
start_urls = ['http://www.laotuzi.com/meizitu/']
def parse(self,response):
item = MztCrawlItem()
item['name'] = response.text
yield item
start_urls
这是一个列表,列表的每一个元素都一个一个url,当我们的爬虫启动的时候会循环这个列表,然后会把url当做请求的地址发送出去,但是在本文件的代码层面上是没有体现的,这里我们点击源码去一探究竟
# 点击scrapy.Spiderr源码中 当我们运行爬虫的时候 就会触发 start_requests 这个方法
def start_requests(self):
# scrapy 默认的起始函数(当执行启动命令时,会触发这个函数)
cls = self.__class__
if not self.start_urls and hasattr(self,'start_url'):
raise AttributeError(
"Crawling could not start: 'start_urls' not found "
"or empty (but found 'start_url' attribute instead,"
"did you miss an 's'?)")
if method_is_overridden(cls,Spider,'make_requests_from_url'):
warnings.warn(
"Spider.make_requests_from_url method is deprecated; it "
"won't be called in future Scrapy releases. Please "
"override Spider.start_requests method instead (see %s.%s)." % (
cls.__module__,cls.__name__
),
)
for url in self.start_urls:
yield self.make_requests_from_url(url)
else:
for url in self.start_urls:
# 每一个url封装成Request对象,交给调度器 这里dont_filter=True 默认不过滤
yield Request(url, dont_filter=True)
这里我们重点是看 else 后面的代码,就先不看前面的两个 if 了,就是遍历然后把每一个url封装成 Request 对象,交给调度器,然后发送请求,默认是GET请求,回调函数是 parse
这里我们也可以自己重写发请求的方法,以及自定义回调函数
import scrapy
class BaiduSpider(scrapy.Spider):
name = 'baidu'
allowed_domains = ['baidu.com']
start_urls = ['http://baidu.com/']
def start_requests(self):
for url in self.start_urls:
# 每一个url封装成Request对象,交给调度器
yield Request(url, dont_filter=True, callback=self.my_parse)
def my_parse(self, response):
print(response.text)
Requests 对象
Request(url[, callback,method='GET', header,body, cookies, meta, encoding='utf-8', priority=0,dont_filte=False, errback])
下面介绍这些参数
- url (string) ---------------> 请求页面的url地址,bytes或者str类型。
- callback (callable) -------> 页面解析函数(回调函数) callable类型 Request对象请求的页面下载完成后,由该参数指定页面解析函数被调用。如果没有定义该参数,默认为parse方法。
- method (string) ---------> http请求的方法,默认为GET
- header (dict) -------------> http 请求的头部字典,dict类型,例如{“Accrpt”:"text/html","User-Agent":"Mozilla/5.0"},如果其中某一项的值为空,就表示不发送该项http头部,例如:{“cookie”:None} 表示禁止发生cookie.
- body (str) -------------------> http请求的正文,bytes或者str类型。
- cookies (dict or cookiejar对象) -----> cookies 信息字典,dict类型。
- meta (dict) ------------------> Request的元素数据字典,dict类型,用于框架中其他组件传递信息,比如中间件Item Pipeline. 其他组件可以使Request对象的meta属性访问该元素字典(request.meta),也用于给响应处理函数传递信息。
- encoding (string) ---------> url和body参数的编码方式,默认为utf-8,如果传入str类型的参数,就使用该参数对其进行编码。
- priority (int) ----------------> 请求的优先级默认为0 ,优先级高的请求先下载。
- dont_filter (boolean) ----> 指定该请求是否被 Scheduler过滤。该参数可以是request重复使用(Scheduler默认过滤重复请求)。但是默认的start_ulrs中的请求是dont_filter = True 不过滤。
- errback (callable) --------> 请求出现异常或者出现http错时的回调函数。
发送post请求的话,这里归纳三种
基于Request对象 发送 Post 请求
这种是最接近底层的,通过自己改写请求方式和构造提交的数据
from scrapy import Request
headers = {'Content-Type':'application/x-www-form-urlencoded'}
data = {'k1':'v1','k2','v2'}
# 通过方法将data的键值对编码成下面这种格式
body = b'k1=v1&k2=v2'
Request(url, method='POST', headers=headers, body=body, callback=self.my_parse)
基于 FromRequest对象 发送 Post 请求
from scrapy import FromRequest
def parse():
data = {} # 以键值对的形式存放要提交的数据 内部会把数据编码成k1=v1&k2=v2这种格式,发送出去
yield scrapy.FromRequest(url, callback=self.my_parse, formdata=data) # 默认不指定请求方式就是POST请求
parse 默认回调函数
Response 对象和常见属性
在 Scrapy 中的 response 是一个基类,根据网站响应内容的不同,
当页面下载完成之后,Scrapy 中的下载器会根据 HTML 响应头部中的 ContentType 信息创建相应的子类对象
url: HTTP相应的 URL地址,str类型的
status: HTTP响应状态码,int类型的(在pycharm的控制台中你可以看到,例如200,404)
headers: 若要获取特定的值用 get('keyname') getlist('keyname')
get('keyname') : 获取指定key的第一个value值 返回str
getlist('keyname') : 获取指定key的所有value值 返回list
body: HTTP响应正文,bytes类型
text: 文本形式的HTTP响应正文,str类型,由response.body使用response.encoding解码得到的
request: 产生该HTTP响应的Requset对象
encoding: HTTP响应正文的编码
meta: response.request.meta 在构造 request 对象的时候,可以将要传递个响应处理函数的信息通过 meta 参数传入;响应处理函数处理响应时候,通过 response.meta 将信息取出
meta 传参
meta(字典)是Request对象中的一个参数,可以在请求和响应之间传递
Request(url=url,meta={'page':'1'})
def paser(self,response)
page = response.meta.get('page') # 获取上次请求中的meta中的page对应的值
new_page = page += 1
url = 'http://www.xiaohua.com/index?page={}'.formate(new_page)
....
yield Request(url=url,meta={'page':new_page})
Don't forget to add your pipeline to the ITEM_PIPELINES setting