项目实战
url = http://books.toscrape.com
页面分析
scrapy shell U R L>
scrapy shell URL>可以使用户在交互式命令行下操作一个Scrapy,通常用来进行前期爬取实验,提高开发效率
scrapy shell http://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html
执行完成后,scrapy shell会使用url参数构造一个response对象,提交给Scrapy引擎,页面下载完成后,程序进入一个Python shell当中,此时环境中已经创建好了一些变量
- request:最近一次下载对应的request对象
- response:最近一次下载对应的response对象
- fetch(req_or_url):用于下载页面,可传入一个request或url,调用后会更新变量request和response
- view(response):用于在浏览器显示response中的页面
view(response)
执行后会在浏览器直接打开页面,但这是由Scrapy下载的页面 ,浏览器直接打开是由浏览器下载的
可以在
分析完书籍页面后,接着分析如何在书籍列表页面中提取每一个书籍页面的链接,在Scrapy shell中,先调用fetch函数下载第一个书籍列表页面,下载后再view函数在浏览器中查看页面
fetch('http://books.toscrape.com')
view(response)
每个书籍页面都可以在每个
from scrapy.linkextractors import LinkExtractor
le = LinkExtractor(restrict_css='article.product_pod')
le.extract_links(response)
编码实现
#创建项目
scrapy startproject toscrape_book
可以使用scrapy genspider name url命令生成模板
cd toscrape_book
scrape genspider books books.toscrape.comm
运行后,genspider创建文件toscrape_book/spiders/books.py,并在其中创建了一个BooksSpider类
在实现spider之前,先定义封装书籍信息Item类,在toscrape_book/items.py中添加
class BookItem(scrapy.Item):
name = scrapy.Field()#书名
price = scrapy.Field()
review_rating = scrapy.Field()#评价等级
review_num = scrapy.Field()
upc = scrapy.Field()#产品编码
stock = scrapy.Field()#库存量
接下来,按照一下五步完成BooksSpider
- 继承Spider创建BooksSpider类(已完成)
- 为spider取名(已完成)
- 指定爬取点(已完成)
- 实现书籍列表页面解析函数
实现书籍页面解析函数
前三部由scrapy genspider命令完成
完成第四步,实现列表页面解析函数parse
parse的任务提取页面中每一个书籍页面的链接,用它们构造request对象并提交
- 提取页面中下一个书籍列表页面的链接,用构造request对象并提交
from scrapy.linkextractors import LinkExtractor
#提取书籍列表页面中的每本书的链接
def parse(self, response):
le = LinkExtractor(restrict_css='article.product_pod h3')
for link in le.extract_links(response):
yield scrapy.Request(link.url,callback=self.parse_book)
# 提取 下一页 的链接
le = LinkExtractor(restrict_css='ul.pager li.next')
links = le.extract_links(response)
if links:
next_url = links[0].url
yield scrapy.Request(next_url,callback=self.parse)
最后完成书籍页面解析函数(parse_book方法)
提取书籍信息存入BookItem对象即可
def parse_book(self,response):
book = BookItem()
sel = response.css('div.product_main')
book['name'] = sel.xpath('./h1/text()').extract_first()
book['price'] = sel.css('p.price_color::text').extract_first()
book['review_rating'] = sel.css('p.star-rating::attr(class)')\
.re_first('start-raing([A-Za-z])')
sel =response.css('table.table.table-striped')
book['upc'] = sel.xpath('(.//tr)[1]/td/text()').extract_first()
book['stock'] = sel.xpath('(.//tr)[last()-1]/td/text()')\
.re_first('\((\d+)available\)')
book['review_num'] = sel.xpath('(.//tr)[last()]/td/text()').extract_first()
yield book
books.py完整代码
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from ..items import BookItem
class BooksSpider(scrapy.Spider):
name = 'books'
allowed_domains = ['books.toscrape.com']
start_urls = ['http://books.toscrape.com/']
#书籍列表页面的解析函数
#提取书籍列表页面中的每本书的链接
def parse(self, response):
le = LinkExtractor(restrict_css='article.product_pod h3')
for link in le.extract_links(response):
yield scrapy.Request(link.url,callback=self.parse_book)
# 提取 下一页 的链接
le = LinkExtractor(restrict_css='ul.pager li.next')
links = le.extract_links(response)
if links:
next_url = links[0].url
yield scrapy.Request(next_url,callback=self.parse)
#书籍页面的解析函数
def parse_book(self,response):
book = BookItem()
sel = response.css('div.product_main')
book['name'] = sel.xpath('./h1/text()').extract_first()
book['price'] = sel.css('p.price_color::text').extract_first()
book['review_rating'] = sel.css('p.star-rating::attr(class)')\
.re_first('start-raing([A-Za-z])')
sel =response.css('table.table.table-striped')
book['upc'] = sel.xpath('(.//tr)[1]/td/text()').extract_first()
book['stock'] = sel.xpath('(.//tr)[last()-1]/td/text()')\
.re_first('\((\d+)available\)')
book['review_num'] = sel.xpath('(.//tr)[last()]/td/text()').extract_first()
yield book
启动spider
scrapy crawl books -o books.csv --nolog
整理列次序
在settings.py中使用FEED_EXPORT_FIELDS指定列次序
FEED_EXPORT_FIELDS = ['UPS','name','price','stock','review_rating','review_num']
改变评级中的 one=1
在pipelines.py中实现BookPipeline
class BookPipeline(object):
review_rating_map = {
'One' = 1,
'Tow' = 2,
'Three' = 3,
'Four' = 4,
'Five' = 5,
}
def provess_item(self,item,spider):
rating = item.get('review_rating')
if rating:
item['review_rating'] = self.review_rating_map[rating]
return item
在settings.py中配置
ITEM_PIPELINES={'toscrape_book.pipelines.BookPipeline':300,}