我目前住在女友家的花场(种花木的花木基地,空气清新并夹杂着混合了泥土味的阵阵猪屎气息,绝对的有益身心),只是美中不足的地方是,由于地方较为偏僻没办法上网。虽然可以通过无线3G上网,但是上网价格明显和工资水平不是一个级别,暂时不考虑。
再说,在花场大部分时间我都不需要用到网络,因为我会把需要用到网络的工作留在公司做,而不需要用到网络的工作才带回花场(比如:设计类、动画类、制作类等)。但有时设计也需要用到素材或是参考一下别的设计的时候,素材倒好办,买DVD或是到电驴上下载回来就行。可是参考设计这个就没有了,于是我就有了一个念头,就是写个爬虫把常用的一些界面设计全部下载到本机来。
非线程版本:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, sys
import urllib
import urllib2
import re
from BeautifulSoup import BeautifulSoup
import chardet
import datetime
get_charset = lambda html: chardet.detect(html)
abspath = os.path.dirname(__file__)
class FC(object):
_base_url_ = None
_list_params_ = None
_urls_ = None
_html_ = None
_start_page_ = 1
_end_page_ = 1
_current_page_ = 1
_soup = None
_begin_time_ = None
_download_dir_ = 'downloads/'
_download_list_ = {}
def __init__(self, base_url, list_param, set_end_page = None):
"""
构造函数
"""
self._begin_time_ = datetime.datetime.now()
self.logging(u'开始运行...')
(self._base_url_, self._list_params_) = (base_url, list_param)
if set_end_page == None and set_end_page > 0:
self.setEndPage()
else:
self._end_page_ = int(set_end_page)
self.logging(u'手动设置列表分页总数为 %d 页...' % set_end_page)
self.loadListPages()
def __del__(self):
"""
析构函数
"""
self.logging(u'执行时间:%d 秒...' % (datetime.datetime.now() - self._begin_time_).seconds)
self.logging(u'结束运行...')
def nextPage(self):
"""
当前页面递加 1
"""
self._current_page_ = self._current_page_ + 1
def setEndPage(self):
"""
设置列表分页总数
"""
self.logging(u'获得并设置列表分页总数...')
html = self.fetchHtml(self.getFirstPageLink())
pager = self._soup.find('td', attrs={'align': 'center', 'bgcolor': '#FFFFFF', 'class': 't14'}).renderContents()
if pager:
href = BeautifulSoup(pager).findAll('a')[-1]['href']
try:
count = re.search('d{2}', href).group()
except:
self.logging('Can not fetch pages count!', 'ERROR')
self._end_page_ = int(count)
self.logging(u'总共 %d 页...' % self._end_page_)
def loadListPages(self):
"""
载入页面列表
"""
self._urls_ = [(self._base_url_ + (self._list_params_ % i)) for i in range(self._start_page_, (self._end_page_ + 1))]
self.logging(u'获得所有列表页面URL...')
def getFirstPageLink(self):
"""
获得第一页的链接
"""
return self._base_url_ + (self._list_params_ % self._start_page_)
def getPageLink(self, page):
"""
获得页面链接
"""
return self._base_url_ + page
def fetchAll(self):
"""
分析列表
"""
self.logging(u'开始分析列表...')
if self._urls_:
for url in self._urls_:
self.fetchListHtml(url)
self.getImgList()
self.logging(u'分析第 %d 页完成,执行时间:%d 秒...' % (self._current_page_, (datetime.datetime.now() - self._begin_time_).seconds))
self.nextPage()
self.logging(u'-----------------------------------------------', 'LINE')
else:
self.logging(u'列表堆栈为空,无法分析...', 'WAITTING')
# 开始下载
# if self._download_list_:
# self.logging(u'开始下载图片...')
# for title in self._download_list_.keys():
# self.download(self._download_list_[title], title)
# self.logging(u'下载完成...')
def fetchListHtml(self, url):
"""
获得列表页HTML
"""
self._soup = None
self.logging(u'开始采集第 %d 页的数据...' % self._current_page_)
try:
html = urllib.urlopen(url).read()
self._soup = BeautifulSoup(html, fromEncoding='utf-8')
self._html_ = self._soup.find('table', attrs={'width': '96%', 'bgcolor': '#efefef', 'cellspacing': '0', 'cellpadding': '0', 'border': '0'}).prettify()
self._html_ = self._encoding(self._html_)
except:
self.logging(u'采集 %s 的数据失败...' % url, 'WAITTING')
html = None
return self._html_
def fetchHtml(self, url, is_prettify = True):
"""
获得页面HTML
"""
self._soup = None
self.logging(u'抓取 %s 的数据...' % url)
try:
html = self.fetch(url)
self._soup = BeautifulSoup(html, fromEncoding='utf-8')
if is_prettify:
self._html_ = self._soup.prettify()
self._html_ = self._encoding(self._html_)
else:
self._html_ = self._soup
except:
self.logging(u'采集 %s 的数据失败...' % url, 'WAITTING')
html = None
return self._html_
def fetch(self, url):
"""
获取内容
"""
try:
opener = urllib2.build_opener(urllib2.HTTPHandler)
opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3')]
opener.addheaders = [('Referer', 'http://www.68design.net/')]
urllib2.install_opener(opener)
response = urllib2.urlopen(url)
return response.read()
except:
self.logging(u'采集 %s 的数据失败...' % url, 'WAITTING')
def getImgList(self):
"""
获得图片列表
"""
self.logging(u'开始获取第 %d 页的图片URL...' % self._current_page_)
try:
tables = self._soup.findAll('table', attrs={'width': '116', 'align': 'center', 'cellspacing': '0', 'cellpadding': '0', 'border': '0'})
except:
self.logging(u'获取失败...', 'WAITTING')
if tables:
self.logging(u'总共获得 %s 条地址' % len(tables))
for table in tables:
link = table.find('a', attrs={'class': 'a04'})['href']
"""
获得列表中的图片
"""
page = self.fetchHtml(self.getPageLink(link), False)
try:
# 标题
title = page.find('td', attrs={'height': '65', 'align': 'center', 'valign': 'bottom', 'class': 't25'}).contents[0]
self.logging(u'获取图片标题为 [%s]...' % title)
# 分页
pagerSoup = page.find('td', attrs={'align': 'center', 'class': 't14', 'width': None, 'height': None})
except:
self.logging(u'获取图片标题失败...', 'WAITTING')
links = self.getImgsPager(pagerSoup)
if links:
imgList = [self.getPageLink(link)] + [self._base_url_ + link for link in links]
else:
imgList = [self.getPageLink(link)]
self._download_list_[title] = self.getImgs(imgList)
def getImgs(self, links):
"""
获得页面中的图片
"""
imgs = []
if links:
for link in links:
page = self.fetchHtml(link, False)
try:
imgs.append(page.find('img', attrs={'onload': 'resizepic(this)'})['src'])
except:
self.logging(u'获取图片地址失败...', 'WAITTING')
return imgs
def getImgsPager(self, pager = None):
"""
获得列表中图片的内容分页列表
"""
if pager:
# 清除重复链接(下一页,上一页,尾页)
return [str(link['href']) for link in pager.findAll('a') if re.search('[d{1|2}]', link.string)]
return None
def download(self, lists, title):
"""
下载图片文件
"""
path = os.path.join(abspath, self._download_dir_, title)
if title:
if os.path.exists(path) == False:
os.mkdir(path)
if lists:
for url in lists:
try:
data = self.fetch(url)
except:
self.logging(u'图片 %s 无法下载...' % url, 'WAITTING')
suffix = url[-3:]
filename = 'image-' + str(lists.index(url) + 1) + '.' + suffix
try:
f = file(os.path.join(path, filename), 'wb')
f.write(data)
f.close()
self.logging(u'写入 [%s] 文件完成...' % filename)
except:
self.logging(u'写入 [%s] 文件失败...' % filename, 'WAITTING')
def _encoding(self, html):
"""
转换编码
"""
charset = get_charset(html)
if charset['encoding'] == 'utf-8':
html = unicode(html, 'utf-8', 'ignore').encode('gbk', 'ignore')
return html
def logging(self, msg, type = 'INFO'):
"""
输出格式化日志
"""
print '[%s] - %s (%s)' % (type, msg, datetime.datetime.now())
def main():
fc = FC('http://www.68design.net/Appreciate/Interface/', 'list-%d.html', 1)
fc.fetchAll()
#lists = fc.getImgs(['http://www.68design.net/Appreciate/Interface/55303-1.html'])
#fc.download(lists, 'hello')
if __name__ == '__main__':
main()
说明:
此程序依赖的包有:
- BeautifulSoup – http://www.crummy.com/software/BeautifulSoup/documentation.zh.html
- chardet – http://chardet.feedparser.org/download/
结语:
我测试爬完第一页用了260秒+(WLAN), 56秒+(LAN),看来无线网卡掉包的厉害呀~~~
写得不好,请别见笑~~~
{PS}
其实我还有一个多线程版本,比这个要快一点,但还是觉得不够好,想做成GUI的。
最主要的原因是,设计图片共94页,每页30组, 每组按平均5张图片计算,每张图片按我爬第一页的平均SIZE: 500Kb计算,就这样也超过4G的数据,以我无线网卡的能力要下载4G估计是很痛苦的事情。
所以,必须要减少分析页面的次数,并可以哪停下哪,以配合我的上班时间。
{OVER}
版权所有,转载请注明出处。
Tags: Python , 爬虫
转载自 <a href="http://www.movoin.com/python-devel-spider.html" title="Python编写蜘蛛/爬虫" rel="bookmark">Python编写蜘蛛/爬虫 | Movoin Studio</a>
