用python中htmlParser实现的spider(python spider)

最近公司网站搞检查,发现了一些问题,一直在用的是xenu工具,速度快,小巧(写了这么多年的MFC,真的很亲切啊,呵呵)

 

刚好这2天才学习python,所以自己写了一个spider,逐渐也对python有了一些了解,下面把源码分享出来,大家可以玩玩看

文件是utf-8格式,但如果加了中文注释,竟然不能debug了。。。无论你是不是在文件头2行加了#encoding=utf-8等方法,有人解决了告诉我一下哦

[c-sharp]  view plain copy
  1. 用python实现的网站spider  
  2. 1.功能:检查死链和空title,链接目前只查属于站内的(包括主站和二级站,并且会过滤重复的URL,防止一个URL多次扫描)  
  3. 2.当页面中有一些错误时,也会提供出错原因和具体位置,所以也可以检查一下网站是否标准  
  4. 3.目前只查页面,不查资源,过滤了 .jpg|.jpeg|.avi|.png|.gif  
  5. 4.依赖:必须安装python-3.2rc1(将来也有可能是正式版,可以自己改test.bat中的python的路径,不过不能装低于这个版本的,3.1版本loggingRotating方式有bug)  
  6. 5.有些不能查出的死链:有时候死链会被重定向到别的页面,如果中国电信会直接跳到它的页面,此情况暂时无法处理,在公司测试没有此现象,adsl上网会这样  
  7. 6.检查网页是否有语法错误,spider.py中  
  8. except HTMLParseError as e:  
  9. #            log.error("HTMLParseError : msg= %s, url= %s, pos= %s" % ( e.msg,  url, lParser.getpos()))  
  10.             pass  
  11. (前提是你已经了解了python的缩进语法)去掉第2行首的“#”即可,目前由于不少网页都有好些小问题,所以默认不开放  
  12. 7.这是方便检查公司网站的小工具,在公司的几个项目网站上测试可用,不过没有在其他大型网站做过性能和兼容性测试,如果你有兴趣,源码都在里面,自己动手玩玩吧  
  13. 8.如果有bug,请反馈给我,也可以自己debug找一下(我的开发环境eclipse + pydev)  
  14. 出错说明:  
  15. 1.URL出错,一般是死链接  
  16. [2011-02-09 11:12:11,392] ERROR : URLError : http://Hardware.global-supplier.com  
  17. [2011-02-09 15:37:57,148] ERROR : HTTPError : code=400, msg= Bad Request, url= http://www.fashionalgifts.com/../company_info.html  
  18. 2.页面解析时出错,下例是tag中内容有问题,pos代表页面的出错位置  
  19. [2011-02-09 11:12:17,119] ERROR : msg= malformed start tag, HTMLParseError : http://fashion.global-supplier.com/cosmetic-bags/pu-cosmetic-bag-gb-c09.html pos= (238, 27)  
  20. 3.urlJoinError,一般是相对路径使用错误导致的,如下,第一个是页面URL,第二个是href中的内容,一级子目录竟然要返回上2级的目录  
  21. UrlJoin Error:http://www.fashionalgifts.com/company-culture.html/, ../../company_info.html  
  22. 不过这样的URL在浏览器中是可以正常执行的。。。太强悍了,帮我们屏蔽错误  
  23. 4.空title  
  24. title is null, url=***  
 

spider.py(主程序)

[c-sharp] view plain copy
  1. #Author:Paul Wang  
  2. #Date:2011-01-26  
  3. #Description:  
  4. from html.parser import HTMLParser  
  5. from html.parser import HTMLParseError  
  6. import urllib.request  
  7. import myLogger  
  8. import myHtmlParse  
  9. import sys  
  10. debugMode = 1  
  11. site = "http://www.geekzones.com/"  
  12. charset = 'utf-8'  
  13. logLever = 'debuG'  
  14. try:  
  15.     def useage():  
  16.         print(" python spider.py siteUrl charSet logLever")  
  17.         print(" example:  python spider.py http://www.baidu.com utf-8 debug")  
  18.           
  19.                   
  20.     def getInnerURL(url,parentUrl,siteName,log):  
  21.         global times  
  22.         global urlList  
  23.         lParser = myHtmlParse.MyParser(log)  
  24.         try:  
  25.             try:  
  26.                   
  27.                 if(url[-1] != '/'):  
  28.                     url += '/'  
  29.                       
  30.                       
  31.                 if url in urlList or len(url) == 0:  
  32.                     return          
  33.                   
  34.                       
  35.                 times += 1  
  36.                 urlList.append(url)  
  37.                 log.info('times = %d open url : %s' % (times , url))  
  38.                                               
  39.                 lParser.currentLink = url;  
  40.                 lParser.siteName = siteName;  
  41.                   
  42.                 opener = urllib.request.build_opener()  
  43.                 opener.addheaders = [('User-agent''Mozilla/5.0')]  
  44.                 htmlSource2 = opener.open(url).read()  
  45.                  
  46.     #            req = urllib.request.Request(url)  
  47.     #            htmlSource2 = urllib.request.urlopen(req).read()  
  48.       
  49.                 lParser.feed(htmlSource2.decode(charset))  
  50.                 lParser.filterRepeatLink()  
  51.                   
  52.                   
  53.                   
  54.                 if(len(lParser.title) == 0):  
  55.                     log.error('title is null, url= %s' % url)  
  56.                       
  57.                  
  58.             except urllib.error.HTTPError as e:  
  59.                 log.error("HTTPError : code=%d, msg= %s, url= %s, parentUrl=%s" % ( e.code, e.msg,  url, parentUrl))  
  60.             except urllib.error.URLError as e:  
  61.                 log.error("URLError : url= %s" % ( url))  
  62.             except HTMLParseError as e:  
  63.                 log.error("HTMLParseError : msg= %s, url= %s, pos= %s, parentUrl=%s" % ( e.msg,  url, lParser.getpos(), parentUrl))  
  64.                   
  65.         finally:  
  66.             lParser.close()  
  67.             for url1 in lParser.link:               
  68.                     if url1 in urlList or len(url1) == 0:  
  69.                         continue                  
  70.                     getInnerURL(url1, url, lParser.siteName,log)  
  71.   
  72.       
  73.     log = myLogger.myLogger('logging.config')  
  74.       
  75.       
  76.     if len(sys.argv) >= 3:  
  77.         site = sys.argv[1]  
  78.         charset = sys.argv[2]  
  79.         log.setLever(sys.argv[3])  
  80.     else:  
  81.         useage()  
  82.         if debugMode != 1:  
  83.             sys.exit()  
  84.         if debugMode == 1:      
  85.             log.setLever("debUG")  
  86.               
  87.       
  88.           
  89.     urlList = urllib.parse.urlparse(site)  
  90.     host = urlList.scheme + '://' + urlList.hostname  
  91.     siteName = host[ host.find('.') +1: ].rstrip('/')  
  92.   
  93.     print(siteName)  
  94. #    sys.exit()  
  95.                  
  96.     times = 0;  
  97.     urlList = []  
  98.     getInnerURL(site, '/',siteName,log)  
  99.   
  100.           
  101. except KeyboardInterrupt:  
  102.     sys.exit()  
  103.       
  104.       

mylogger.py

[c-sharp]  view plain copy
  1. #Author:Paul Wang  
  2. #Date:2011-01-26  
  3. #Description:logging wrapper  
  4. import logging.config  
  5. class myLogger:  
  6.       
  7.       
  8.     LEVELS = {'debug': logging.DEBUG,  
  9.           'info': logging.INFO,  
  10.           'warning': logging.WARNING,  
  11.           'error': logging.ERROR,  
  12.           'critical': logging.CRITICAL}  
  13.     def __init__(self, configName):  
  14.         print('init logger...')  
  15.         logging.config.fileConfig(configName)  
  16.         self.logger = logging.getLogger("simpleExample")  
  17.    
  18.           
  19.     def setLever(self, leverName):  
  20.         if (len(leverName)==0 ):  
  21.             self.logger.setLevel(logging.NOTSET)  
  22.         else:  
  23.             self.logger.setLevel(  
  24.                 self.LEVELS.get(leverName.lower(), logging.NOTSET))  
  25.               
  26.         print('set lever %s...' % logging.getLevelName(self.logger.level) )  
  27.           
  28.       
  29.     def writeLog(self, msg):  
  30.         self.logger.log(self.logger.level, msg)  
  31.           
  32.     def debug(self, msg):  
  33.         self.logger.debug(msg)  
  34.       
  35.     def info(self, msg):  
  36.         self.logger.info(msg)  
  37.           
  38.     def warn(self, msg):  
  39.         self.logger.warn(msg)  
  40.           
  41.     def error(self, msg):  
  42.         self.logger.error(msg)  
  43.           
  44.     def critical(self, msg):  
  45.         self.logger.critical(msg)  
  46.               
  47.           
  48.     def __del__(self):  
  49.         print('destructor logger...')  
  50.           
 

myHtmlParse.py

[c-sharp]  view plain copy
  1. #Author:Paul Wang  
  2. #Date:2011-01-26  
  3. from html.parser import HTMLParser  
  4. import urllib  
  5. import re  
  6. import myLogger  
  7. class  MyParser(HTMLParser):  
  8.     def   __init__ (self,log):  
  9.             HTMLParser. __init__ (self)  
  10.             self.currentLink = ''  
  11.             self.link = []  
  12.             self.exlink = []  
  13.             self.host = ''  
  14.             self.siteName = '' #like 'baidu.com'  
  15.             self.title = ''  
  16.             self.titleFlag = 0  
  17.             self.log = log  
  18.               
  19.     def  handle_starttag(self, tag, attrs):              
  20.         if  tag == 'a' :  
  21.             if len(attrs)==0:pass  
  22.             for  name, value  in  attrs:  
  23.                 if  name == 'href' :  
  24.                     pattern = re.compile('(.jpg|.jpeg|.avi|.png|.gif)</p>,re.I)  
  25.                     match = pattern.search(value)  
  26.                     if match:  
  27.                         continue  
  28.                       
  29.                     if len(value) and value[0] != '#' and value.find('@') == -1:  
  30.                         if value.find(self.siteName) != -1 /  
  31.                          or value[0] == '/' /  
  32.                          or value[0:2] == './' /  
  33.                          or value[0:3] == '../':  
  34.                               
  35.                             if(self.currentLink[-1] != '/'):  
  36.                                 self.currentLink += '/'  
  37.                                   
  38.                             url = urllib.request.urljoin(self.currentLink, value)  
  39.                               
  40.                             if(url.find("..") != -1 ):  
  41.                                 self.log.error("UrlJoin Error:%s, %s" % (self.currentLink, value))  
  42.                               
  43.                             self.link.append( url)  
  44.                         else:  
  45.                             self.exlink.append(value.rstrip('/'))  
  46.         elif tag == 'title':  
  47.             if len(attrs)==0:pass  
  48.             self.titleFlag = 1  
  49.       
  50.     def handle_data(self, data):  
  51.         if self.titleFlag == 1 and len(self.title)== 0:  
  52.             self.title=data  
  53.             self.titleFlag = 0  
  54.               
  55.     def filterRepeatLink(self):  
  56. #        print('count1: %d' % len(self.link))  
  57.         dict = {}  
  58.         for keys in self.link:  
  59.             dict.setdefault(keys, '111')  
  60.          
  61. #        print('count2: %d' % len(dict))  
  62.         self.link = dict.keys()  
  63.          
  64. #        print('count2: %d' % len(self.link))  
  65.        
 

logging.config(配置档,用过log4c等的一看就明白了)

[c-sharp]  view plain copy
  1. [loggers]  
  2. keys=root,example  
  3. [handlers]  
  4. keys=consoleHandler,timedRotatingFileHandler  
  5. [formatters]  
  6. keys=simpleFormatter  
  7. [formatter_simpleFormatter]  
  8. #format=[%(asctime)s]%(name)s : %(message)s  
  9. format=[%(asctime)s] %(levelname)s : %(message)s  
  10. [logger_root]  
  11. level=DEBUG  
  12. handlers=consoleHandler,timedRotatingFileHandler  
  13. [logger_example]  
  14. level=DEBUG  
  15. handlers=consoleHandler,timedRotatingFileHandler  
  16. qualname=example  
  17. propagate=0  
  18. [handler_consoleHandler]  
  19. class=StreamHandler  
  20. level=DEBUG  
  21. formatter=simpleFormatter  
  22. args=(sys.stdout,)  
  23. [handler_rotateFileHandler]  
  24. class=handlers.RotatingFileHandler  
  25. level=DEBUG  
  26. formatter=simpleFormatter  
  27. args=('test.log''a', 1024*1024, 9)  
  28. [handler_timedRotatingFileHandler]  
  29. class=handlers.TimedRotatingFileHandler  
  30. level=ERROR  
  31. formatter=simpleFormatter  
  32. args=('app.log','d')  

你可能感兴趣的:(用python中htmlParser实现的spider(python spider))