写在开始:
学习网址>>>> https://segmentfault.com/a/1190000003870052 scrapy.ItemLoad>>>http://docs.pythontab.com/scrapy/scrapy0.24/topics/loaders.html 流程>>>http://www.jianshu.com/p/5b6fbf9245f8 翻页>>>http://blog.sina.com.cn/s/blog_737463190102wk8x.html Log>>>http://blog.csdn.net/arbel/article/details/7781121 一些注意点>>>> 网站: 网站每页有多个meizi主题,每页页码格式:http://www.meizitu.com/a/list_1_1.html 进入某个meizi内容页面,页码格式:http://www.meizitu.com/a/5460.html 每个页面包括多张图片,具体图片地址:http://mm.howkuai.com/wp-content/uploads/2016a/09/02/01.jpg 网站列表页格式有更改,len(pages)会进入无限循环 网站增加了检查,需增加headers item: 使用ItemLoader来进行数据归集 spider: yield有迭代功能,代替循环 首页,爬虫入口,中部是图片链接,下部有分页信息 列表页,由分页信息进来,爬虫获得后续的url,每个列表页下部有分页 内容页,由首页和列表页url过来处理,获得下载图片的url 流程: 开始页:start_urls=('http://www.meizitu.com/a/list_1_1.html',) 获取当前列表页中内容页链接:for link in sel.xpath(''//li[@class="wp-item"]/div/h3/a/@href').extract()>>> 处理第一个内容页:[callback=self.parse_item]>>> 获取内容页中图片链接:l.add_xpath('image_urls', "//div[@id='picture']/p/img/@src", Identity())>>> 循环处理内容页中图片[pipeline] 转入下一内容页[yield request] ...... 文件页列表集合:pages=sel.xpath('//*[@id="wp_page_numbers"]/ul/li/a/@href').extract() 下一页地址: page_link=pages[-2] 转入下一列表页[yield request]>>> 转入第一个内容页>>>获取内容页中图片链接>>>循环处理内容页中图片 转入下一内容页>>>获取内容页中图片链接>>>循环处理内容页中图片 pipeline: 需要增加header logging: 没有成功,后续再完善
1.需建创建scrapy的project,可以新建一个CreateProj.py的文件;并且在参数中输入新建项目的名称
# -*- coding: utf-8 -*-
from scrapy import cmdline
#创建一个Project,需要在parameter中填定startproject YOUR_PROJECT_NAME
cmdline.execute()
2.定义ITEM,一般建立在items.py
import scrapy
#定义Item类,用以存储spider获取的所需要数据
class MeizituItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
url = scrapy.Field() #处理页面地址
name = scrapy.Field() #文件名
tags = scrapy.Field() #标签
image_urls = scrapy.Field() #图片网络链接地址
images = scrapy.Field() #图片本地存储地址
3.创建spider,这里有两个不同的spider
A.MeiziSpider,用的是循环列表页地址来进行处理
# -*- coding: utf-8 -*-
import scrapy
#Selector refer http://scrapy-chs.readthedocs.io/zh_CN/0.24/topics/selectors.html
from scrapy.selector import Selector
#Item Loader provide an easy way to catch:Items
from scrapy.contrib.loader import ItemLoader,Identity
from meizitu.items import MeizituItem
class MeiziSpider(scrapy.Spider):
name="meizitu"
allowed_domains=["meizitu.com"] #No need http://
start_urls=('http://www.meizitu.com/a/list_1_1.html',) #start webpage
def parse(self,response):
print "开始爬虫>>>>>>>>>>>>>>>>>>>>>>>>>>>"
#sel是页面源代码,载入scrapy.selector转成xpath/CSS
sel=Selector(response)
#连接用@href属性,获取图片链接
for link in sel.xpath('//li[@class="wp-item"]/div/h3/a/@href').extract():
#请求=Request(连接,parse_item),用以处理当前页面信息
print "当前列表页中内容页链接->>>"+str(link)
request=scrapy.Request(link,callback=self.parse_item)
yield request #返回至请求
#获取页码集合
pages=sel.xpath('//*[@id="wp_page_numbers"]/ul/li/a/@href').extract()
#获取当前页
# page = sel.xpath('//*[@id="wp_page_numbers"]/ul/li[@class="thisclass"]')
# page=page[0].text
print 'pages: %s'%pages,type(pages) #打印当前页码
if len(pages)>9: #当#如果页码集合>某一值
page_link=pages[-2] #下一页=读取页码集合的倒数每二个页码
page_link=page_link.replace('/a/','') #图片连接=page_link(a替换为空)
request=scrapy.Request('http://www.meizitu.com/a/%s' % page_link,
callback=self.parse) #处理下一页
print "下一页是->>>" + str(page_link)
yield request #返回请求
def parse_item(self,response):
#l=用ItemLoader载入MeizituItem()
print "处理内容页存入ITEM-->>>"+str(response)
l=ItemLoader(item=MeizituItem(),response=response)
#name
l.add_xpath('name','//h2/a/text()')
#tags
l.add_xpath('tags', "//div[@id='maincontent']/div[@class='postmeta clearfix']/div[@class='metaRight']/p/text()")
#picture link
l.add_xpath('image_urls', "//div[@id='picture']/p/img/@src", Identity())
#url
l.add_value('url',response.url)
return l.load_item()
B.mzt_Spider运用rules来进行迭代匹配列表,有个缺点是旁边的页码也会进行循环
# -*- coding: utf-8 -*-
#another spider for meizitu which use LinkExtractor
from scrapy.selector import Selector #引入Selector分析xpath
from scrapy.contrib.spiders import CrawlSpider,Rule #引入爬虫
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.contrib.loader import ItemLoader,Identity
from meizitu.items import MeizituItem #引入item类
class mzt_Spider(CrawlSpider): #定义spider
name="mzt" #定义spider名称
allowed_domains=["meizitu.com"] #定义spider限制区域
start_urls=["http://www.meizitu.com/a/list_1_1.html"] #spider开始
rules=[
#CrawlSpider匹配列表页规则,用以翻页
#follow = True表示会在返回的url中继续寻找符合条件的url,\d+
Rule(SgmlLinkExtractor(allow=(r'http://www.meizitu.com/a/list_1_\d\.html')),
follow=True),
#CrawlSpider匹配下一层规则
Rule(SgmlLinkExtractor(allow=(r'http://www.meizitu.com/a/\d+\.html')),
#使用函数进行处理
callback="parse_item"),
]
def parse_item(self,response):
#l=用ItemLoader载入MeizituItem()
print "处理内容页存入ITEM-->>>"+str(response)
l=ItemLoader(item=MeizituItem(),response=response)
#name
l.add_xpath('name','//h2/a/text()')
#tags
l.add_xpath('tags', "//div[@id='maincontent']/div[@class='postmeta clearfix']/div[@class='metaRight']/p")
#picture link
l.add_xpath('image_urls', "//div[@id='picture']/p/img/@src", Identity())
#url
l.add_value('url',response.url)
return l.load_item()
4.建立pipeline,一般作为数据存储,这里添加了将ITEM写入txt功能。
import requests
from meizitu import settings
import os
#网站增加验证,需增加headers
head= {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) '
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36'}
class ImageDownloadPipeline(object):
def process_item(self, item, spider):
print "开始pipeline-->"
if 'image_urls' in item: #如果'图片地址'在项目中
print "开始图片保存-->"
images=[]
#自定义存储目录
dir_path='%s\\%s' %(settings.IMAGES_STORE,spider.name)
# print dir_path
if not os.path.exists(dir_path): #判别地址是否存在
os.makedirs(dir_path) #建创文件夹
#循环图片地址
for image_url in item['image_urls']:
chunkSize=1024 #单次请求最大值
us=image_url.split('/')[3:] #文件地址按/分割
image_file_name='_'.join(us) #命名为文件名
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,headers=head,stream=True) #need to set steam=True parameter
for chunk in response.iter_content(chunk_size=chunkSize):
if chunk:
handle.write(chunk) #保存图片
handle.close()
item['images']=images #images信息存入ITEM[images]
print "开始保存TXT>>>>>>"
f=open("mzt.txt",'a+')
for key in item: #循环item,格式为dict
f.write(key)
f.write(":")
for i in item[key]: #循环item内容,格式为list
i=i.encode('utf-8') #需要转码
i=str(i).replace("\r\n","")
f.write(i)
f.write("\n")
f.close()
return item
5.进行settings.py的设置
BOT_NAME = 'meizitu' #->MeiziSpider
# BOT_NAME = 'mzt' #->mzt_Spider
SPIDER_MODULES = ['meizitu.spiders']
NEWSPIDER_MODULE = 'meizitu.spiders'
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.5 ' \
'(KHTML, like Gecko) Chrome/19.0.1084.54 Safari/536.5'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = 0.25
ITEM_PIPELINES = {
'meizitu.pipelines.ImageDownloadPipeline': 1}
#存储地址
IMAGES_STORE="C:\\Users\\zhengt\\Desktop\\mzt" #存储地址
6.创建一个run_meizitu.py进行运行spider
# -*- coding: utf-8 -*-
# 新建一个运行爬虫的模块
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from meizitu.spiders.MeiziSpider import MeiziSpider #引入spider类
from meizitu.spiders.mzt_Spider import mzt_Spider #引入spider类
# 获取setting.py模块设置
settings = get_project_settings() # 设置
process = CrawlerProcess(settings=settings)
# 添加spider,可以添加多个spider
process.crawl(MeiziSpider)
# process.crawl(mzt_Spider)
# 启动spider
process.start()
结果,运行了5分钟,下了10M,68个项目。
后续:logging没有成功.
来源:oschina
链接:https://my.oschina.net/u/2718942/blog/813138