1.总之先启动
先安装scrapy,
pip install scrapy
创建scrapy项目, 生成的项目结构应该如图所示,
scrapy startproject example
选择需要爬取的页面并分析,这里选定的页面是All products | Books to Scrape - Sandbox一个供给爬虫学者练手的网站,我们需要爬取上面的书籍信息,解析我们需要的内容在那一段html标签里可以使用浏览器自带的开发者工具进行查看。
找到我们想要的数据在哪里之后,我们就可以开始编写爬虫代码了,
在exmaple/spiders目录下创建新爬虫文件文件book_spider.py,然后在这里面开始实现代码
# -*- coding: utf-8 -*
import scrapy
class BooksSpider(scrapy.Spider):
# 每一个爬虫的唯一标识
name = "books"
# 定义爬虫爬取的起始点,起始点可以是多个,这里只有一个
start_urls = ["http://books.toscrape.com/"]
def parse(self, response):
# 提取数据
for book in response.css("article.product_pod"):
name = book.xpath("./h3/a/@title").extract_first()
price = book.css("p.price_color::text").extract_first()
yield {
"name": name,
"price": price,
}
# 提取链接
next_url = response.css("ul.pager li.next a::attr(href)").extra
if next_url:
next_url = response.urljoin(next_url)
yield scrapy.Request(next_url, callback=self.parse)
每个我们自己定义的爬虫都需要三个因素,name:唯一标识,start_urls:起始爬取url,parse:解析方法。
运行爬虫,
scrapy crawl books -o books.csv
圆满完成。
2.为什么可以这样?
scrapy的架构如下,
数据管道:负责处理爬取到的数据
调度器:负责对提交的下载请求进行调度
中间件:处理request和response
下载器:下载页面
scrapy的工作过程如下,
当SPIDER要爬取某URL地址的页面时,需使用该URL构造一个 Request对象,提交给ENGINE。 Request对象随后进入SCHEDULER按某种算法进行排队,之后的 某个时刻SCHEDULER将其出队,送往DOWNLOADER。
DOWNLOADER根据Request对象中的URL地址发送一次HTTP请求到网站服务器,之后用服务器返回的HTTP响应构造出一个 Response对象,其中包含页面的HTML文本。
Response对象最终会被递送给SPIDER的页面解析函数(构造 Request对象时指定)进行处理,页面解析函数从页面中提取 数据,封装成Item后提交给ENGINE,Item之后被送往ITEM PIPELINES进行处理,最终可能由EXPORTER以某种数据格式写入文件(csv,json);另一方面,页 面解析函数还从页面中提取链接(URL),构造出新的Request 对象提交给ENGINE。
3.Request和Response对象
Request对象用来描述一个HTTP请求,
Request(url, callback, method='GET', headers, body, cookies, meta,
encoding='utf-8', priority=0, dont_filter=False, errback=None)
url:请求页面的url地址,bytes或str类型, 如'http://www.python.org/doc'。
callback:页面解析函数, Callable类型,Request对象请求的页面下载完成后,由该参数指定的页面解析函数被调用。如果未传递该参数,默认调用Spider的parse方法.
method:HTTP请求的方法,默认为'GET'。
headers:HTTP请求的头部字典,dict类型,例如{'Accept': 'text/html', 'User-Agent':Mozilla/5.0'}。如果其中某项的值为None,就表示不发送该项HTTP头部,例如{'Cookie': None},禁止发送Cookie。
body:HTTP请求的正文,bytes或str类型。
cookies:Cookie信息字典,dict类型,例如{'currency': 'country': 'UY'}。
meta:'USD', Request的元数据字典,dict类型,用于给框架中其他组件传递信息,比如中间件Item Pipeline。其他组件可以使用 Request对象的meta属性访问该元数据字典 (request.meta),也用于给响应处理函数传递信息,详见 Response的meta属性。
encoding:url和body参数的编码默认为'utf-8'。如果传入的url或body 参数是str类型,就使用该参数进行编码。
priority:请求的优先级默认值为0,优先级高的请求优先下载。
dont_filter:默认情况下(dont_filter=False),对同一个url地址多次提 交下载请求,后面的请求会被去重过滤器过滤(避免重复下 载)。如果将该参数置为True,可以使请求避免被过滤,强制 下载。例如,在多次爬取一个内容随时间而变化的页面时(每 次使用相同的url),可以将该参数置为True。
errback:请求出现异常或者出现HTTP错误时(如404页面不存在)的回调函数
Response对象用来描述一个HTTP响应,根据响应内容可以有TextResponse,HtmlResponse,XmlResponse,三种类型。
属性与方法有很多,最常用的有css,xpath,urljoin。
4.提取数据的方式
Selector提取有两种方式,css或xpath,都是返回一个SelectorList对象,可以使用正常的for进行遍历。
但首先需要先构建selector对象,1.使用原生的html格式,2.使用response 对象
from scrapy.selector import Selector
text = '''
<html>
<body>
<h1>Hello World</h1>
<h1>Hello Scrapy</h1>
<b>Hello python</b>
<ul>
<li>C++</li>
<li>Java</li>
<li>Python</li>
</ul>
</body>
</html>
'''
selector = Selector(text=text)
response = HtmlResponse(url='http://www.example.com', body=body)
selector = Selector(response=response)
选中元素,
selector_list = selector.xpath('//h1')
selector_list[0].extract()
selector_list.extract_first()
selector_list[0].re()
selector_list.re_first()
在我们的实际使用过程中几乎不需要自己定义selector对象,Response对象内部会以自身为参数自动创建Selector对象,并将该Selector对象缓存,以便下次使用。调用更加简洁。
response.xpath('.//h1/text()').extract()
response.css('li::text').extract()
5.使用自定义数据类处理数据
我们自定义的数据类主要放在item.py文件中,一个文件可以定义多个数据类。
Item基类:自定义数据类(如BookItem)的基类。
Field类:用来描述自定义数据类包含哪些字段(如name、price等)。
自定义一个数据类,只需继承Item,并创建一系列Field对象的类 属性(类似于在Django中自定义Model)即可。如下,你甚至还可以在自己自定义的代码上进行扩展。
from scrapy import Item, Field
class BookItem(Item):
name = Field()
price = Field()
class ForeignBookItem(BookItem):
translator = Field()
在Field中,你便可以对数据进行一些处理,
authors = Field(serializer=lambda x: '|'.join(x))
其中,元数据的键serializer是CsvItemExporter规定好的,它会 用该键获取元数据,即一个串行化函数对象,并使用这个串行化函数将 authors字段串行化成一个字符串。