本文分为两部分,去哪儿网图片爬虫和Scrapy使用详解。Scrapy使用详解基于去哪儿网图片爬虫进行解析说明。
去哪儿网图片爬虫
- 目录结构
$ scrapy startproject TourLib
Scrapy组件说明
- Scrapy Engine(Scrapy引擎)
Scrapy引擎是用来控制整个系统的数据处理流程,并进行事务处理的触发。更多的详细内容可以看下面的数据处理流程。 - Scheduler(调度)
调度程序从Scrapy引擎接受请求并排序列入队列,并在Scrapy引擎发出请求后返还给他们。 - Downloader(下载器)
下载器的主要职责是抓取网页并将网页内容返还给蜘蛛( Spiders)。 - Spiders(蜘蛛)
蜘蛛是有Scrapy用户自己定义用来解析网页并抓取制定URL返回的内容的类,是用来定义特定网站的抓取和解析规则。
蜘蛛的整个抓取流程(周期)是这样的:
- 首先获取第一个URL的初始请求,当请求返回后调取一个回调函数(parse(self, response))。第一个请求是通过调用start_requests()方法。该方法默认从start_urls中的Url中生成请求,并执行解析来调用回调函数。
- 在回调函数(parse)中,你可以解析网页响应并返回项目对象和请求对象或两者的迭代。这些请求也将包含一个回调(scrapy.Request(links, callback=self.parse_item)),然后被Scrapy下载,然后有指定的回调parse_item
(self, response)处理。 - 在回调函数parse_item中,你解析网站的内容,使用的是Xpath选择器(但是你也可以使用BeautifuSoup, lxml或其他任何你喜欢的程序),并生成解析的数据项。
- 最后,从蜘蛛返回的项目通常会进驻到Item Pipeline(项目管道)。
- Item Pipeline(项目管道)
项目管道的主要责任是负责处理有蜘蛛从网页中抽取的项目,他的主要任务是清洗、验证和存储数据。当页面被蜘蛛解析后,将被发送到项目管道,并经过几个特定的次序处理数据。每个项目管道的组件都是有一个简单的方法组成的Python类。他们获取了项目并执行他们的方法,同时他们还需要确定的是是否需要在项目管道中继续执行下一步或是直接丢弃掉不处理。
项目管道通常执行的过程有:
- 清洗HTML数据
- 验证解析到的数据(检查项目是否包含必要的字段)
- 检查是否是重复数据(如果重复就删除)
- 将解析到的数据存储到数据库,将解析到的图片存储到硬盘
piplines就干了两件事,每次spider处理好一个页面,将图片信息传给它,1.图片存到硬盘,2.信息存到数据库
- Downloader middlewares(下载器中间件)
下载中间件是位于Scrapy引擎和下载器之间的钩子框架,主要是处理 Scrapy引擎与下载器之间的请求及响应。它提供了一个自定义的代码的方式来拓展Scrapy的功能。下载中间器是一个处理请求和响应的钩子框架。他是 轻量级的,对Scrapy尽享全局控制的底层的系统。 - Spider middlewares(蜘蛛中间件)
蜘蛛中间件是介于Scrapy引擎和蜘蛛之间的钩子框架,主要工作是处理蜘蛛 的响应输入和请求输出。它提供一个自定义代码的方式来拓展Scrapy的功能。蛛中间件是一个挂接到Scrapy的蜘蛛处理机制的框架,你可以插入自定义 的代码来处理发送给蜘蛛的请求和返回蜘蛛获取的响应内容和项目。 - Scheduler middlewares(调度中间件)
调度中间件是介于Scrapy引擎和调度之间的中间件,主要工作是处从Scrapy引擎发送到调度的请求和响应。他提供了一个自定义的代码来拓展Scrapy的功能。前阵子想爬点二手车数据赚钱,专门捣鼓了一两个星期的scrapy,虽然最后因为各种原因,赚钱并不如意,但也学到了爬虫的一些基本技术,现在记录下来,以备后续使用。
添加mysql支持
- settings.py中添加如下配置项
# start MySQL database configure setting
MYSQL_HOST = 'localhost'
MYSQL_DBNAME = 'cnblogsdb'
MYSQL_USER = 'root'
MYSQL_PASSWD = 'root'
# end of MySQL database configure setting
- 在piplines.py中添加数据库操作如下:
class ImageDownloadPipeline(object):
def process_item(self, item, spider):
db = MySQLdb.connect("localhost","root","mypassword","test_db" )
cursor = db.cursor()
if 'image_urls' in item:
images = []
dir_path = '%s/%s/%s' % (settings.IMAGES_STORE,item['place'],item['name'])
##item['url'] = <200 www.explame.com>
urls = str(item['url'])[5:-1]
if not os.path.exists(dir_path):
os.makedirs(dir_path)
for image_url in item['image_urls']:
image_file_name = image_url[-15:]
file_path = '%s/%s' % (dir_path, image_file_name)
images.append(file_path)
if os.path.exists(file_path):
continue
with open(file_path, 'wb') as handle:
response = requests.get(image_url, stream=True)
for block in response.iter_content(1024):
if not block:
break
handle.write(block)
sql = "INSERT INTO tour_tbl (tour_title,tour_icourl,local_url) VALUES ( '%s','%s','%s' )" % ( image_file_name,image_url,urls)
try:
# 执行sql语句
cursor.execute(sql)
# 提交到数据库执行
db.commit()
except:
# 发生错误时回滚
db.rollback()
item['images'] = images
# 关闭数据库连接
db.close()
return item
- 在settins.py中添加ImageDownloadPipeline
ITEM_PIPELINES = {'qunar.pipelines.ImageDownloadPipeline': 1}
Xpath使用
示例
xpath类似beautifulsoup解析html结构,省去了正则表达式的麻烦
<html>
<head></head>
<body>
<div>
<p><a href="http://www.iana.org"> more information </a></p>
</div>
</body>
</html>
- xpath('//div//a')
[<a href="http://www.iana.org"> more information </a>] - xpath('//div/*')
div中所有元素 - xpath('//div/a/@href')
[http://www.iana.org] - xpath('//div/a/text()').extract()
'more information'
xpath参考教程
这是个视频教程,是我学习xpath的最好的教程,看完真的是一下就明白了。
XPath 与多线程爬虫
Scrapy定向爬虫教程(二)——提取网页内容
多页面爬取
多页面爬取有两种形式
1)从某一个或者多个主页中获取多个子页面的url列表,parse()函数依次爬取列表中的各个子页面。
#先获取url list,然后根据list爬取各个子页面内容
fromtutorial.items import DmozItem
classDmozSpider(scrapy.Spider):
name = "dmoz"
allowed_domains = ["dmoz.org"]
start_urls =["http://www.dmoz.org/Computers/Programming/Languages/Python/",]
def parse(self, response):
for href inresponse.css("ul.directory.dir-col > li > a::attr('href')"):
#获取当前页面的url:respone.url
#通过拼接response.url和href.extract(),将相对网址转换为绝对网址
url =response.urljoin(response.url, href.extract())
yield scrapy.Request(url, callback=self.parse_dir_contents)
#负责子页面内容的爬取
def parse_dir_contents(self, response):
for sel in response.xpath('//ul/li'):
item = DmozItem()
item['title'] =sel.xpath('a/text()').extract()
item['link'] = sel.xpath('a/@href').extract()
item['desc'] =sel.xpath('text()').extract()
yield item
2)从递归爬取,这个相对简单。在scrapy中只要定义好初始页面以及爬虫规则rules,就能够实现自动化的递归爬取。
yield和return的区别
- yield
yield是用于生成器。什么是生成器,你可以通俗的认为,在一个函数中,使用了yield来代替return的位置的函数,就是生成器。它不同于函数的使用方法是:函数使用return来进行返回值,每调用一次,返回一个新加工好的数据返回给你;yield不同,它会在调用生成器的时候,把数据生成object,然后当你需要用的时候,要用next()方法来取,同时不可逆。你可以通俗的叫它"轮转容器",可用现实的一种实物来理解:水车,先yield来装入数据、产出generator object、使用next()来释放;好比水车转动后,车轮上的水槽装入水,随着轮子转动,被转到下面的水槽就能将水送入水道中流入田里。
def func3():
for i in range(1,5):
yield i#装入
gob = func3()#generator 类型
print next(gob)#1 释放的第一个装入的数据,(先入先出)
print next(gob)#2
print next(gob)#3
print next(gob)#4
print next(gob)#报错
个人理解,yield在python内部是当作list处理的:
def func3():
for i in range(1,5):
yield i
yi = []
yi = func3()
for y in yi:
print y
输出:
1
2
3
4
- return
这个大家都知道,return既可以终止函数的执行,也可以返回函数加工处理好的数据。