Python抓图脚本

实习期太无聊了,前两周才决定开始看一看被大家推崇的高开发效率的python。打算用python来写个东西,正好在python分区看到有人写了类似的demo,好吧,咱就写这个。在周六上午dota连跪几把后才开始写,周日晚上才能运行。 在某网站下了几百M,测试还算可行。 然后,这两天又修修补补,现在还算比较稳定吧。拿出来给大家批评教育下,毕竟也没写过python。 好了废话不多说,上菜!

注:用的是python 3.3 

       使用了htmlparser 来分析网页数据、抓取链接, 然后创建了一个ScratchFactory类来过滤链接、保存图片。ScratchFactory 继承了threading.Thread 是一个独立的线程其中下载每个图片也是并发的。

       另外开了两个全局变量 UrlSrc、UrlDiged来存储抓取的链接和遍历过的链接。  

但是并发不一定好,因为如果你请求太快,网站服务器会认为是ddos攻击,拒绝连接的。所以我在主线程里限制了线程数量,还有给每个请求设置时间间隔,防止出现DDos类似效果。

主线程中控制速度:


01 while True:
02         iflen(threading.enumerate()) > THREAD_NUM:       
03             continue
04         mLock.acquire()
05         if UrlSrc.__len__():
06             temp = UrlSrc.pop(0)
07             = ScratchFactory(temp)
08             UrlDiged.append(temp)
09             t.start()
10         mLock.release()
11         #打印当前连接数、线程数、urlsrc+urldiged表长
12         print("Conections:",UrlSrc.__len__(),"*****threads:",\
13               len(threading.enumerate()),"****TableLength:",\
14               (len(UrlSrc)+len(UrlDiged))/1000
15         if time.localtime().tm_min%2 == 0 \
16         and time.time() - savetime > 60 :
17             save()                 #保存现场
18             savetime = time.time()
19         time.sleep(SLEEP_TIME)


以下是两个主要类:

MyHtmlParser 

继承于 HTMLParser,主要用来分析html文本,提取出标题、编码方式、链接和图片链接

ScratchFactory

主要有这几个函数:

addHeader: 这个是给提取的是相对路径的链接加上头变成绝对路径

clearData: 这个过滤提取的链接, 过滤title

saveImage:开线程给save下载图片

run:

因为保存图片的path和文件名是根据抓取页面的title来命名的,因为中文涉及到编码的问题,编码方式一般都是放在http的响应头里面,但我不知道在python里面如何获得响应头(知道的请告诉我一声),只好在html文本里的<meta>标签里去找了。(这个问题已经解决,采用了@pjx2013 的方法使用了chardet,chardet在python3下运行不了,不过有个大哥把chardet修改了)  感谢 @pjx2013. 

http://www.cnblogs.com/dajianshi/archive/2012/12/18/2827083.html

这里的feed是不接受字节类型的, 所以强制把它转成 utf-8,然


01 conect = urllib.request.urlopen(self.url)    #下载网页数据
02             data = conect.read()
03             conect.close()
04             htmlx = MyHtmlParser()
05             htmlx.feed(data[:500].decode('utf-8','ignore'))       
06             = htmlx.charset                            #获得html编码
07             if == '':
08                 = 'gb2312'
09             htmlx.reset()
10             htmlx.feed(data.decode(t,'ignore'))
11             self.title = htmlx.title


总的来说 MyHtmlParser写得很垃圾,还可以改进的。 原本偷懒觉得用htmlparser方便,结果发现还是用来很多正则表达式。

下面是源码:

有'<-'的地方可以根据需要修改的, 如果不断出现 10054 应该是请求速度过快了

view source
print ?
001 '''
002 Created on 2013-2-1
003 @author: 李鹏飞
004 @mailto: [email protected]
005 运行环境:Python 3
006 '''
007 #coding:utf-8
008 import re
009 import urllib.request
010 from html.parser import HTMLParser
011 from html.parser import HTMLParseError
012 import os
013 import threading
014 import time
015 import chardet
016  
017 class MyHtmlParser(HTMLParser):
018     def __init__(self):
019         HTMLParser.__init__(self)
020         self.url = []
021         self.img = []
022         self.title = []
023     def handle_starttag(self, tag, attrs):
024         if tag == "a":
025             for in attrs:
026                 if i[0== "href":
027                     self.url.append(i[1])
028         elif tag == "title":
029             self.title = 1
030         for in attrs:
031             if re.match('http://.+\.(jpg|jepg|png)',str(i[1])):
032                 self.img.append(i[1])
033          
034     def handle_data(self, data):
035         if self.title == 1:
036             self.title = data
037         findimg = re.findall('http://.+?\.jpg',data)
038         for in range(0,len(findimg)):
039                     findimg[i] = findimg[i]
040         self.img += findimg
041              
042     def handle_startendtag(self, tag, attrs):
043         if tag == "a":
044             for in attrs:
045                 if i[1== "href":
046                     self.url.append(i[1])
047         for in attrs:
048             if re.match('http://.+\.(jpg|jepg|png)',str(i[1])):
049                 self.img.append(i[1])
050  
051 class ScratchFactory(threading.Thread):
052     def __init__(self,url):
053         threading.Thread.__init__(self)
054         self.url = url
055         self.tempImgs = []
056         self.tempUrls = []
057         self.title = []
058         global seed
059         match = re.search(seed + '.*/',url)
060         if match:
061             self.pwd = match.group()
062              
063     def addHeader(self,data):
064         global seed
065         for in range(0,len(data)):
066             if re.match("http.+", data[i]) == None:
067                 if re.match("/.*",data[i]):
068                     data[i] = seed + data[i]
069                 elif re.match('./.*',data[i]):
070                     data[i] = self.pwd + data[i][2:]
071                 else:
072                     data[i] = self.pwd + data[i]
073         returndata                  
074     def run(self):
075         try:
076             conect = urllib.request.urlopen(self.url)    #下载网页数据
077             data = conect.read()
078             conect.close()
079             htmlx = MyHtmlParser()
080             = chardet.detect(data)                     #获得html编码
081             if t['encoding']:
082                 charset = t['encoding']
083             else:
084                 charset = 'utf-8'
085             htmlx.feed(data.decode(charset,'ignore'))
086             self.title = htmlx.title
087             self.tempUrls = self.addHeader(htmlx.url)    #给相对路径链接加上头
088             self.tempImgs = self.addHeader(htmlx.img)
089             htmlx.close()
090             self.clearData()                             #过滤无用链接
091             threading.Thread(target = \
092                              self.saveImages,args = () ).start()  #下载图片
093         except HTMLParseError as e:
094             print("####Error : 1 ######:",e , '--->',  self.url)
095         except Exception as e:
096             print("####Error : 2 ######:",e , '--->' self.url)
097          
098         global UrlSrc,UrlDiged,mLock
099         mLock.acquire()
100         = []
101         for temp in self.tempUrls:
102             if not UrlDiged.__contains__(temp):
103                 t.append(temp)
104         = []
105         for temp in t:
106             if not UrlSrc.__contains__(temp):
107                 l.append(temp)
108         UrlSrc += l
109         mLock.release()
110      
111     def clearData(self):
112         #去除重复链接
113         self.tempUrls = set(self.tempUrls)
114         self.tempImgs = set(self.tempImgs)
115         global seed
116         = []
117         for temp in self.tempUrls:                    #<-链接过滤,正则表达式
118             if re.match(seed + "/.*", temp):
119                 t.append(temp)
120         self.tempUrls = t
121          
122         = []
123         for temp in self.tempImgs:                    #<-图片过滤,正则表达式
124             ifre.match(".+.(gif|jpg|png)",temp):               
125                 t.append(temp)
126         self.tempImgs = t
127         self.title = re.split('(-|_)',self.title)[0]  #<-页面标题分隔,截取title中关键字
128         #去除title中非法字符
129         self.title =self.title.replace(' ','')              
130         self.title = self.title.replace('/','')
131         self

你可能感兴趣的:(Python抓图脚本)