前言:关于scrapy的介绍网上有很多,在实现这个爬图片过程也遇到很多坑,我用的是python2.7.15,scrapy版本是1.5,遇到问题时可以根据自己的开发环境寻找对应的帮助文档。先说说主要思路:
1.先了解scrapy,这个是介绍的挺好的文章,还有实战观看
2.分析网站结构,确定爬取策略
3.根据爬虫过程中遇到的问题进行解决,如设置代理,user-agent,禁用cookie等等即防反爬策略
本来想对着那个教程做的一个爬取美女图片,但是鉴于女票不给,所以爬一个帅哥图片的网站,首先是新建项目,在命令行新建一个scrapy项目,并且为这个项目新建一个爬虫程序:具体的步骤是——
在命令行中输入 (1)scrapy startproject BoyDemo,进入该项目,输入(2)scrapy scrapy genspider -t boy nanrentu.cc,此时把项目复制到eclipse的新建的一个pydev project里面,然后配置好运行方式,具体参考环境配置,然后开始写代码了。
这个是我的例子的大体结构,spiders里面就放爬虫程序,cmdline就是用来启动爬虫程序的,items相当于实体类,存放对应的东西,piplines就是处理实体类的,settings是配置文件,middlewears是中间件处理(个人理解是给爬虫制定策略去更好地爬取),其中cmdline是要自己创建的,我们要先做一些配置:
1.用户代理池的设置:
在middlewares.py找到xxxDownloaderMiddleware,这个是下载器中间件里面有一个process_request方法,我们可以对这个方法进行编写:
def process_request(self, request, spider):
user_agent_pools=[
'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3',
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3',
]
ua=random.choice(user_agent_pools)
print '当前使用的user-agent是'+ua
try:
request.headers.setdefault('User-Agent',ua)
except Exception,e:
print e
pass
return None
2.ip代理池的配置,我一开始不会爬取,然后多次访问被封我ip了,不能访问那个网站了,所以ip代理池就可以减少爬取不了目标网站,可以在middlewares新建一个类,
class MyproxiesSpiderMiddleware(HttpProxyMiddleware):
def __init__(self,ip=''):
self.ip=ip
self.IPPOOL=[
{'ipaddr': 'http://116.213.98.6:8080'},
{'ipaddr': 'https://60.176.227.182:8118'},
{'ipaddr': 'https://114.239.125.251:61234'},
{'ipaddr': 'https://220.191.15.49:6666'},
{'ipaddr': 'https://222.185.160.95:6666'},
{'ipaddr': 'http://111.155.116.234:8123'},
{'ipaddr': 'http://122.114.31.177:808'},
]
def process_request(self, request, spider):
thisip=random.choice(self.IPPOOL)
print("this is ip:"+thisip["ipaddr"])
request.meta['proxy']=thisip["ipaddr"]
return None
要确保你的ip是可用的,可以上一些免费代理网站查,然后上一些可以检测ip的网站看是否可用,因为刚入门,那些自动爬取有效ip代理池放进数据库,再取出来用的操作还不会,然后在middlewares对进行修改后,就要到settings文件去启用这个下载中间件。
DOWNLOADER_MIDDLEWARES = {
'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware':123,
'middlewares.MyproxiesSpiderMiddleware':125,
'middlewares.HandsomeboyDownloaderMiddleware':2
}
本来是被注释掉的,这时候启用并写上你的中间件执行顺序,,值越小越先执行。
设置好ip和用户代理池以后,爬虫在访问网站时候就会自动带上这些信息去访问
3.不遵循robot.txt设置,禁用cookie:
在setting上配置:
ROBOTSTXT_OBEY = False
COOKIES_ENABLED = False
4.使pineline可用,就是爬虫执行完parse等一系列方法后,会给item赋值,item返回后又会在pineline文件里面得到相应的处理,要使处理生效,就要在setting文件里面配置
ITEM_PIPELINES = {
'pipelines.HandsomeboyPipeline': 300,
}
这时候setting文件就配置完毕
spider的编写,比较重要的点就是xpath的使用和深度爬取得应用,下面说明:
def parse(self, response):
urldata = response.xpath("/html/body/div[@id='nav']/div[@class='nav']/ul//li/a/@href").extract()
print urldata
boy = urldata[3]
yield Request(boy,callback=self.next,dont_filter=True)
这个方法是爬虫的一开始的方法,就是获取首页的某个页面的地址,然后调用next方法,一步步调用,其余代码:
def next(self, response):
page_last = response.xpath("/html/body/div[@id='parta']/div[@id='partac']/div[@class='pagelist']/a[last()]/@href").extract_first()
if page_last != None:
i = page_last.find("_")
i2 = page_last.find(".")
str1 = page_last[i+3:i2]
page_num = str1.encode('utf-8')
page_a = int(page_num)
for n in range(1,page_a+1):
time.sleep(1)
page_url = 'http://www.nanrentu.cc/rh/'+'list_4_'+str(n)+'.html'
request = scrapy.Request(page_url,callback=self.next2,dont_filter=True)
yield request
def next2(self, response):
page_title_list = response.xpath("/html/body/div[@id='parta']/div[@id='partac']/div[@class='partacpic']/ul[@class='P2']//li/a/@title").extract()
page_url_list = response.xpath("/html/body/div[@id='parta']/div[@id='partac']/div[@class='partacpic']/ul[@class='P2']//li/a/@href").extract()
boy_page_url = page_url_list[0]
boy_page_url = 'http://www.nanrentu.cc'+boy_page_url
yield Request(boy_page_url,callback=self.next3,dont_filter=True)
def next3(self, response):
num = response.xpath("/html/body/div[@id='parta']/div[@class='nc']/div[@class='pagelist']/a/span/b/text()").extract()
url_pre = response.url
s = url_pre.split('.')[:-1]
b = s[0]+'.'
c = s[1]+'.'
d = s[2]
e =b + c +d
time.sleep(1)
for x in range(1,int(num[0])+1):
if x == 1:
page_url = e+'.html'
else:
page_url = e+'_'+str(x)+'.html'
yield Request(page_url,callback=self.getPic,dont_filter=True)
def getPic(self,response):
item = HandsomeboyItem()
pic_url = response.xpath("/html/body/div[@id='parta']/div[@class='nc']/div[@class='imgbox']/div[@class='piccontext']/div[@class='picshow']/div[@class='picshowtop']/a/img/@src").extract()
pic_url = 'http://www.nanrentu.cc'+pic_url[0]
item['url'] = pic_url
return item
最后的getPic就给item赋值并返回item,item就会被相应的管道处理,主要是下载图片,这个类是pinepline文件的一个类
class HandsomeboyPipeline(object):
def process_item(self, item, spider):
this_url = item['url']
id = re.findall('http://www.nanrentu.cc/uploads/allimg/(.*?).jpg',this_url)
a = id[0].find('/')
id = id[0][a+1:]
print id
file = 'D:/temp/' + id + '.jpg'
print('Downloading :' , file)
urllib.urlretrieve(this_url, filename=file)
print('Final Download :' , file)
return item
其他的要注意的就是包,类的导入正确与否,要结合自己版本来查看。