scrapy简单介绍,以及使用scrapy爬豆瓣音乐
基本概念介绍SpiderSelectorsitemitem pipelineDownloader Middlewarescrapy内置交互环境例子:爬取豆瓣音乐创建项目创建Item创建Spider创建pipline:将数据存储到csv文件加入一个middleware用于记录日志settings.py运行
基本概念介绍
Spider
Spider定义了网站是如何被扒取的,通过Spider可以决定哪些url可以被扒,决定解析response中的哪些数据。
Spider大致工作流程:
- 通过start_requests()方法执行第一个请求,可以不自定义start_requests方法,默认的实现是通过make_requests_from_url对start_urls中url生成request,并默认回调parse方法。
- 在回调方法里,通过xpath selector(或其他方式)解析html数据。回调方法返回Item对象或者request对象,或者两者的迭代。
- 最后,Item对象可以通过Item Pipeline存储到数据库,或者通过Feed exports导出为json或cvs等文件上。
Selectors
Selector用于从原始的html数据中提取出我们想要的数据。基于XPath和CSS表达式实现,可以通过response.XPath和response.CSS得到Selector对象(列表)。
Selector有4个基本方法
- xpath(xPathexpression):根据XPath规则返回Selector对象列表
- css(CSSexpression):根据CSS规则返回Selector对象列表
- extract():返回unicode字符串内容
- re():根据正则表达式,返回符合要求的unicode字符串
item
item用于存储扒下来的数据,类似于django中的model,但它更简单-只有一种field。scrapy还为item提供了跟操作字典一样的接口,因此你可以像操作dict那样操作item。
item pipeline
- 净化html数据
- 验证item的有效性,无效则返回DropItem忽略不处理
- 检查是否重复爬取了
- 把item存入数据库
- 把item导出到csv/xml。。。通过与ItemExport配合
Downloader Middleware
非常类似于django的Middleware,适合想在request前和收到response后做些处理。
scrapy内置交互环境
在终端中通过执行scrapy shell http://www.douban.com
指令可以进入到scrapy的交互界面,用dir()
可以看到内置变量,通过它们可以进行我们想要的操作,比如通过sel我们可以进行xpath提出元素。
例子:爬取豆瓣音乐
创建项目
xxxxxxxxxx
scrapy startproject doubancrawler
创建Item
item.py
x
#items.py
import scrapy
class AlbumItem(scrapy.Item):
name=scrapy.Field()
artist=scrapy.Field()
intro=scrapy.Field()
tag=scrapy.Field()
musics=scrapy.Field()
class TagItem(scrapy.Item):
name=scrapy.Field()
创建Spider
xxxxxxxxxx
#douban_music.py
# -*- coding: utf-8 -*-
import scrapy
from doubancrawler import items
from scrapy.utils.response import get_base_url
import urlparse
class DoubanMusicSpider(scrapy.Spider):
name = "douban_music"
allowed_domains = ["douban.com"]
start_urls = (
"http://music.douban.com/tag/",
)
def parse(self,response):
self.log("%s,%d"%(response.url,response.status),level=scrapy.log.WARNING)
tagLinks=response.xpath("//table[@class='tagCol']")[0].xpath(".//td/a")
baseUrl=get_base_url(response)
for tag in tagLinks:
yield items.TagItem(name=tag.xpath("./text()").extract()[0])
absolutUrl=urlparse.urljoin(baseUrl,tag.xpath("./@href").extract()[0])
yield scrapy.Request(absolutUrl,callback=self.parse_album_list)
def parse_album_list(self,response):
for url in response.xpath("//tr[@class='item']/td/a/@href").extract():
yield scrapy.Request(url,callback=self.parse_album_detail)
def parse_album_detail(self,response):
item=items.AlbumItem()
#name
name=response.xpath("//div[@id='wrapper']/h1/span/text()").extract()[0]
item["name"]=name.strip()
#artist/tag
info=response.xpath("//div[@id='info']")
trans={
"表演者:":"artist",
"流派:":"tag",
}
for infoitem in info.xpath(".//span[@class='pl']"):
key=infoitem.xpath("./text()").extract()[0].strip()
if not key in trans:
continue
value=infoitem.xpath("./a/text()").extract()[0]
item[trans[key]]=value
#intro
introlist=response.xpath("//div[@id='link-report']/span/text()").extract()
item["intro"]=introlist and introlist[0] or ""
#musics
musics=response.xpath("//li[@class='song-item']/div[1]/text()").extract()
item["musics"]="|".join(musics)
return item
创建pipline:将数据存储到csv文件
#pipelines.py
from scrapy import signals
from scrapy.contrib.exporter import CsvItemExporter
from items import AlbumItem,TagItem
class CvsPipline(object):
def __init__(self):
self.files = {}
def from_crawler(cls, crawler):
pipeline = cls()
crawler.signals.connect(pipeline.spider_opened, signals.spider_opened)
crawler.signals.connect(pipeline.spider_closed, signals.spider_closed)
return pipeline
def spider_opened(self, spider):
tagFile= open('%s_tags.csv' % spider.name, 'w+b')
albumFile= open('%s_albums.csv' % spider.name, 'w+b')
self.files[spider] = (tagFile,albumFile)
self.tagExporter = CsvItemExporter(tagFile)
self.albumExporter = CsvItemExporter(albumFile)
self.tagExporter.start_exporting()
self.albumExporter.start_exporting()
def spider_closed(self, spider):
self.tagExporter.finish_exporting()
self.albumExporter.finish_exporting()
tagFile,albumFile=self.files.pop(spider)
tagFile.close()
albumFile.close()
def process_item(self, item, spider):
if isinstance(item,TagItem):
self.tagExporter.export_item(item)
elif isinstance(item,AlbumItem):
self.albumExporter.export_item(item)
return item
加入一个middleware用于记录日志
#middlewares.py
class MyDownloadMiddleware(object):
def process_response(self,request,response,spider):
spider.log("%s,%d"%(response.url,response.status),level=scrapy.log.WARNING)
import time
print response.url,response.status,time.time()
return response
settings.py
在settings.py上配置middleware和pipline,以及反爬虫策略。
xxxxxxxxxx
BOT_NAME = 'doubancrawler'
SPIDER_MODULES = ['doubancrawler.spiders']
NEWSPIDER_MODULE = 'doubancrawler.spiders'
import sys
reload(sys)
sys.setdefaultencoding('gbk')
LOG_LEVEL="WARNING"
LOG_FILE="scrapy.log"
ITEM_PIPELINES = {
'doubancrawler.pipelines.CvsPipline': 1000,
}
DOWNLOADER_MIDDLEWARES = {
'doubancrawler.middlewares.MyDownloadMiddleware': 543,
}
#防止爬虫被封
DOWNLOAD_DELAY = 2
RANDOMIZE_DOWNLOAD_DELAY = True
USER_AGENT="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.91 Safari/537.36"
COOKIES_ENABLES=False
运行
cd到项目主目录,执行命令
xxxxxxxxxx
scrapy crawl douban_music