Python编写蜘蛛/爬虫
luyued 发布于 2011-01-19 06:46 浏览 N 次我目前住在女友家的花场(种花木的花木基地,空气清新并夹杂着混合了泥土味的阵阵猪屎气息,绝对的有益身心),只是美中不足的地方是,由于地方较为偏僻没办法上网。虽然可以通过无线3G上网,但是上网价格明显和工资水平不是一个级别,暂时不考虑。
再说,在花场大部分时间我都不需要用到网络,因为我会把需要用到网络的工作留在公司做,而不需要用到网络的工作才带回花场(比如:设计类、动画类、制作类等)。但有时设计也需要用到素材或是参考一下别的设计的时候,素材倒好办,买DVD或是到电驴上下载回来就行。可是参考设计这个就没有了,于是我就有了一个念头,就是写个爬虫把常用的一些界面设计全部下载到本机来。
doubanclaimc2f07f0f2b624272
非线程版本:
#!/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}
既然来了,也许你也会想看一下:
上一篇:虎门服交会昨晚冷风中火爆开幕 下一篇:Weight Loss: 5 Truths
相关资讯
- 07-01· 禁教唐诗算术能还幼儿快
- 07-01· 2011年06月17日
- 07-01· 唐诗宋词英译:李商隐 筹
- 07-01· 仿评《唐诗1000首》第186首
- 07-01· 没事干的时候背背唐诗吧
- 07-01· [转载]唐诗中“斜”字该读
- 07-01· 湖南醴陵瓷业转型升级
- 07-01· 奇瑞风云2两厢黑色|2010款
- 07-01· 摩根士丹利华鑫摩根士丹
- 07-01· 摩根士丹利华鑫近期优选
图文资讯
最新资讯
- 07-01· 中金投行部大摩出售中金
- 07-01· 摩根士丹利招聘6月2日【实
- 07-01· 营养防病圣典
- 07-01· 《博伽梵歌原意》之第十
- 07-01· [不错]斑斓圣典---减肥中常
- 07-01· 武乐圣典《太极武当》:武
- 07-01· 铁血英雄-现阶段战功牌兑
- 07-01· 2011年06月10日【原创】南歌
- 07-01· 【淘宝网信息】- 2010年的
- 07-01· 深圳品牌女装有哪些?