返回列表 发帖

Python写的一个简单的爬虫-多线程

  1. # -*- coding: utf-8 -*-

  2. import re
  3. import urllib2
  4. import urlparse
  5. import threading
  6. import Queue
  7. import sys
  8. import time
  9. import os
  10. count = 0
  11. re_href = re.compile('href="([^"]*)"')
  12. url_dict = {'http://www.baidu.com':'1'}
  13. total_url_list = []

  14. def url_open(url):    #get html页面
  15.      
  16.     headers={
  17.             "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
  18.             #"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
  19.             #"Accept-Language": "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3",
  20.             #"Accept-Encoding": "gzip, deflate",
  21.             #"If-Modified-Since": "Tue, 03 Dec 2010 08:25:11 GMT",
  22.             #"Cache-Control": "max-age=0"
  23.             }
  24.     try:
  25.         req = urllib2.Request(url,headers = headers)
  26.         html= urllib2.urlopen(req,timeout=3).read()
  27.         ret = '200'
  28.         return html,ret
  29.     except urllib2.HTTPError, e:
  30.         #print u'error:', e.code
  31.         return '',e.code
  32.     except :
  33.         pass
  34.         return '','99999'

  35.      
  36. def keyword_check(url,keyword):  #检查关键字
  37.     str1 = ".*"
  38.     keyword = str1 + keyword
  39.     re_keyword = re.compile(keyword)
  40.     if re_keyword.match(url):
  41.         return 'true'
  42.     else:
  43.         return 'false'

  44. def html_open(html,response_code): #抓取html页面内a标签内的href
  45.     url_list = []
  46.     if response_code == '200':
  47.         list_1st = re.findall(re_href,html)
  48.         list_2nd = list(set(list_1st))     
  49.         return list_2nd
  50.     else:
  51.         return url_list

  52. def check_url(url):   #跟字典内比较,检查url是否重复
  53.     if url in url_dict.keys():
  54.         #print 'in the dictionary'
  55.         return 'true'
  56.     else:
  57.         #print 'not in the dictionary'
  58.         global count
  59.         count = count + 1
  60.         return 'false'
  61.      
  62. def clean_list(root_url,url_list,key): #整理url列表,返回整理后的列表
  63.     keyword = key
  64.     #print keyword,len(url_list)
  65.     new_list = []
  66.     if len(url_list) == 0:
  67.         return []
  68.     else:
  69.         for url in url_list:
  70.             url_parse = urlparse.urlparse(url)
  71.             if url_parse[0] == '' and url_parse[1] == '':
  72.                 temp_root_url = urlparse.urlparse(root_url)
  73.                 url = temp_root_url[0]+'://'+temp_root_url[1]+'/'+url_parse[2]
  74.             url_parse = urlparse.urlparse(url)
  75.             if url_parse[0] == 'http' :  #the whitelist
  76.                 path = url_parse[2]
  77.                 if path[-3:] not in ['css','png','pdf','jsp','zip','rar','doc','jpg','JPG','DOC','xls']: #the blacklist
  78.                     t = urlparse.urlunparse(url_parse)
  79.                     if check_url(t) == 'false':  #检查url是否在字典内,若不是,进行下一个判断
  80.                         if keyword_check(t,keyword) == 'true':
  81.                             #print keyword_check(t,keyword)
  82.                             new_list.append(t)         
  83.         return new_list
  84.      
  85. def put_url_list_in_dict(url_list):  #把队列转换成字典,并返回
  86.     if len(url_list) == 0:
  87.         temp_dict = {}
  88.         return temp_dict
  89.     else:
  90.         temp_dict = {}.fromkeys(url_list,1)
  91.         return temp_dict


  92. class SpiderThread(threading.Thread):    #爬虫线程类
  93.     def __init__(self, urlqueue, readurls, key, deep):
  94.         threading.Thread.__init__(self)
  95.         self.urlqueue = urlqueue
  96.         self.key = key
  97.         self.readurls = readurls
  98.         self.deep = deep
  99.         self.urls = readurls
  100.     def geturl(self, urltuple):     
  101.         deep_count, url = urltuple  #对应赋值
  102.         if  deep_count < self.deep: # 判断是否到达层数
  103.             #print 'go',url
  104.             html,response_code = url_open(url)  #打开url 返回 html页面和响应码
  105.             #print response_code
  106.             url_list = html_open(html,response_code)   #传入 html 返回 url列表
  107.             #print url_list
  108.             cleaned_list = clean_list(url,url_list,self.key) #传入url列表  返回整理后的url列表
  109.             #print cleaned_list
  110.             if len(cleaned_list) != 0 :   #如果整理后的url列表不为空,全部导入字典
  111.                 temp_dict = put_url_list_in_dict(cleaned_list)
  112.                 global url_dict
  113.                 url_dict = dict(url_dict.items() + temp_dict.items())
  114.                 #print len(url_dict)
  115.             for url in cleaned_list:      #把整理好的url列表全部导入队列
  116.                 self.urlqueue.put((deep_count+1, url))
  117.     def run(self):
  118.         while True:
  119.             urltuple = self.urlqueue.get() #从队列里获取一个URL
  120.             #print self.urlqueue.qsize() 此线程获取的目前队列长度
  121.             global total_url_list
  122.             deep_count, url = urltuple   #深度 ,URL 对应赋值
  123.             total_url_list.append(url)
  124.             #print u'抓取 URL:', self.urlqueue.qsize(), deep_count, url   
  125.             self.geturl(urltuple) #运行geturl,传入urltuple值
  126.             self.urlqueue.task_done() # 向url队列发送信号

  127. def write_in_txt(url_list,url,start_time):   #写如txt函数,参数:url列表,根url(命名用),开始时间
  128.     print len(url_list)
  129.     set_url_list = list(set(url_list))
  130.     print len(set_url_list)
  131.     set_url_list.sort()
  132.     url_parse = urlparse.urlparse(url)
  133.     pc_username = os.popen('cd').readline()
  134.     Desktop_addr = '%s\log_%s.txt'%(pc_username[0:-1],url_parse[1])
  135.     file_object = open(Desktop_addr, 'w')
  136.     spend_time = time.time()-start_time
  137.     file_object.write(str(spend_time)+'\n')
  138.     file_object.write(str(len(set_url_list))+'\n')
  139.     for i in set_url_list:
  140.         file_object.write(i+'\n')
  141.     print 'write done'

  142. def monitor_url_list(urlqueue,interval_time,start_time):
  143.     global total_url_list
  144.     global count
  145.     while 1:
  146.         time.sleep(1)
  147.         if not urlqueue.qsize() < 0:
  148.             print 'The crawler have analyzed ',len(total_url_list),'URL','  Spent %.2f s!!'%(time.time()-start_time),'   The total number of url : ',urlqueue.qsize()
  149.             time.sleep(interval_time-1)
  150.         if urlqueue.qsize() == 0:
  151.             break
  152.      


  153. def work(url, deep, threads, key):
  154.     start_time = time.time()
  155.     urlqueue = Queue.Queue(0)
  156.     readurls = []
  157.     deep = deep + 1
  158.     for i in range(threads):          #启动线程 threads 是线程个数
  159.         r = SpiderThread(urlqueue,readurls,key,deep)
  160.         r.setDaemon(True)
  161.         r.start()
  162.     monitor_thread = threading.Thread(target = monitor_url_list,args = (urlqueue,10,start_time))  #监听线程(监听全局变量total_url_list的个数)
  163.     monitor_thread.start()

  164.     urlqueue.put((1,url))   #把原始url放入队列
  165.     urlqueue.join()     #队列执行 join 操作,实际上意味着等到队列为空,再退出主程序。
  166.     print '----------------------------------------'
  167.     write_in_txt(total_url_list,url,start_time)  #写函数
  168.     print 'spend time:',time.time()-start_time
  169. #a = {'1':'2','3':'4','5':'6','7':'8','9':'q'}
  170. #b = {'1':'2','33':'43','54':'6a','d':'8e','9e':'q'}
  171. #print a,b
  172. #print dict(a.items()+b.items())
  173. if __name__ == "__main__":
  174.     try:
  175.         a = work('http://www.cits.com.cn/',5,10,'cits')
  176.          
  177.     except KeyboardInterrupt:     
  178.         print "User Press Ctrl+C,Exit"
复制代码

返回列表