POP Article V2.0 设为主页
收藏本站
首 页交流论坛留 言
您现在的位置:首 页 >> Python 与 XML >> Python开发 >> 查看文章
python写的多线程代理服务器(1)
作者:tamsyn  来源:www.sqlite.com.cn  时间:2007-12-17  【 字体: 】 〖 双击滚屏 〗

用php写过一个,不过由于 php 不支持多线程,抓取和验证速度都非常的慢
(尽管libcurl可以实现多线程抓取,但他也只限于抓取网页这个功能,抓回来的数据进行再处理很麻烦).

于是决定用python重新写,python支持多线程啊。
已经有一年多没有用过 python了,很多语法,语言特性都快忘记得差不多了。 经过三天业余时间的
摸索,今天我写的这个程序终于可以和大家交流了。

下面放出源代码: 希望有高手能帮我共同完善,
这个程序是我学python语言以来写的第二个程序,应该有很多写得不够简洁的地方,希望行家多多指点

程序现有功能:
   1. 能自动从12个网站抓取代理列表,并保存到数据库里面
   2. 自动验证每个代理是否可用,并保存验证时的响应时间做为判断代理速度的依据
   3.  能分类输出代理信息, 已验证的,未验证的,高度匿名代理,普通匿名代理,透明代理到不同文件
   4   支持的输出格式有 xml,htm,csv,txt,tab   每种文件都能自定义字段和格式
   5.  扩展性比较强, 要添加一个新的抓取网站只需要改变一个全局变量,添加两个函数 (有详细接口说明)
   6.   用 sqlite 做数据库,小巧,方便,简单,0配置,0安装,放在屁股口袋里就可以带走
   7.  多线程抓取,多线程验证

我的运行环境:windows xp  + python v2.4 ,其他版本未测试

程序下载:   点击这里(242kb)


代码的注释非常详细,python 初学者都可以看懂, 12个网站抓取分析的正则表达式都有详细注释

  1 # -*- coding: gb2312 -*-
  2 # vi:ts=4:et
  3 
  4 """
  5 目前程序能从下列网站抓取代理列表
  6 
  7 http://www.cybersyndrome.net/
  8 http://www.pass-e.com/
  9 http://www.cnproxy.com/
 10 http://www.proxylists.net/
 11 http://www.my-proxy.com/
 12 http://www.samair.ru/proxy/
 13 http://proxy4free.com/
 14 http://proxylist.sakura.ne.jp/
 15 http://www.ipfree.cn/
 16 http://www.publicproxyservers.com/
 17 http://www.digitalcybersoft.com/
 18 http://www.checkedproxylists.com/
 19 
 20 问:怎样才能添加自己的新网站,并自动让程序去抓取?
 21 答:
 22 
 23 请注意源代码中以下函数的定义.从函数名的最后一个数字从1开始递增,目前已经到了13    
 24 
 25 def build_list_urls_1(page=5):
 26 def parse_page_2(html=''):
 27 
 28 def build_list_urls_2(page=5):
 29 def parse_page_2(html=''):
 30 
 31 .......
 32 
 33 def build_list_urls_13(page=5):
 34 def parse_page_13(html=''):
 35 
 36 
 37 你要做的就是添加 build_list_urls_14 和 parse_page_14 这两个函数
 38 比如你要从 www.somedomain.com 抓取 
 39     /somepath/showlist.asp?page=1
 40     ...  到
 41     /somepath/showlist.asp?page=8  假设共8页
 42 
 43 那么 build_list_urls_14 就应该这样定义
 44 要定义这个page这个参数的默认值为你要抓取的页面数8,这样才能正确到抓到8个页面
 45 def build_list_urls_14(page=8):   
 46     ..... 
 47     return [        #返回的是一个一维数组,数组每个元素都是你要抓取的页面的绝对地址
 48         'http://www.somedomain.com/somepath/showlist.asp?page=1',
 49         'http://www.somedomain.com/somepath/showlist.asp?page=2',
 50         'http://www.somedomain.com/somepath/showlist.asp?page=3',
 51         ....
 52         'http://www.somedomain.com/somepath/showlist.asp?page=8'
 53     ]
 54 
 55 接下来再写一个函数 parse_page_14(html='')用来分析上面那个函数返回的那些页面html的内容
 56 并从html中提取代理地址
 57 注意: 这个函数会循环处理 parse_page_14 中的所有页面,传入的html就是那些页面的html文本
 58 
 59 ip:   必须为 xxx.xxx.xxx.xxx 数字ip格式,不能为 www.xxx.com 格式
 60 port: 必须为 2-5位的数字
 61 type: 必须为 数字 2,1,0,-1 中的其中一个。这些数字代表代理服务器的类型
 62       2:高度匿名代理  1: 普通匿名代理  0:透明代理    -1: 无法确定的代理类型
 63  #area: 代理所在国家或者地区, 必须转化为 utf8编码格式  
 64 
 65 def parse_page_14(html=''):
 66     ....
 67     return [
 68         [ip,port,type,area]         
 69         [ip,port,type,area]         
 70         .....                      
 71         ....                       
 72         [ip,port,type,area]        
 73     ]
 74 
 75 最后,最重要的一点:修改全局变量 web_site_count的值,让他加递增1  web_site_count=14
 76 
 77 
 78 
 79 问:我已经按照上面的说明成功的添加了一个自定义站点,我要再添加一个,怎么办?
 80 答:既然已经知道怎么添加 build_list_urls_14 和 parse_page_14了
 81 
 82 那么就按照同样的办法添加
 83 def build_list_urls_15(page=5):
 84 def parse_page_15(html=''):
 85 
 86 这两个函数,并 更新全局变量   web_site_count=15
 87 
 88 """
 89 
 90 
 91 import urllib,time,random,re,threading,string
 92 
 93 web_site_count=13   #要抓取的网站数目
 94 day_keep=2          #删除数据库中保存时间大于day_keep天的 无效代理
 95 indebug=1
 96 
 97 thread_num=100                   # 开 thread_num 个线程检查代理
 98 check_in_one_call=thread_num*25  # 本次程序运行时 最多检查的代理个数
 99 
100 
101 skip_check_in_hour=1    # 在时间 skip_check_in_hour内,不对同一个代理地址再次验证
102 skip_get_in_hour=8      # 每次采集新代理的最少时间间隔 (小时)
103 
104 proxy_array=[]          # 这个数组保存将要添加到数据库的代理列表 
105 update_array=[]         # 这个数组保存将要更新的代理的数据 
106 
107 db=None                 #数据库全局对象
108 conn=None
109 dbfile='proxier.db'     #数据库文件名
110 
111 target_url="http://www.baidu.com/"   # 验证代理的时候通过代理访问这个地址
112 target_string="030173"               # 如果返回的html中包含这个字符串,
113 target_timeout=30                    # 并且响应时间小于 target_timeout 秒 
114                                      #那么我们就认为这个代理是有效的 
115 
116 
117 
118 #到处代理数据的文件格式,如果不想导出数据,请让这个变量为空  output_type=''
119 
120 output_type='xml'                   #以下格式可选,  默认xml
121                                     # xml
122                                     # htm           
123                                     # tab         制表符分隔, 兼容 excel
124                                     # csv         逗号分隔,   兼容 excel
125                                     # txt         xxx.xxx.xxx.xxx:xx 格式
126 
127 # 输出文件名 请保证这个数组含有六个元素
128 output_filename=[
129             'uncheck',             # 对于未检查的代理,保存到这个文件
130             'checkfail',           # 已经检查,但是被标记为无效的代理,保存到这个文件
131             'ok_high_anon',        # 高匿代理(且有效)的代理,按speed排序,最块的放前面
132             'ok_anonymous',        # 普通匿名(且有效)的代理,按speed排序,最块的放前面
133             'ok_transparent',      # 透明代理(且有效)的代理,按speed排序,最块的放前面
134             'ok_other'             # 其他未知类型(且有效)的代理,按speed排序
135             ]
136 
137 
138 #输出数据的格式  支持的数据列有  
139 # _ip_ , _port_ , _type_ , _status_ , _active_ ,
140 #_time_added_, _time_checked_ ,_time_used_ ,  _speed_, _area_
141 
142 output_head_string=''             # 输出文件的头部字符串
143 output_format=''                  # 文件数据的格式    
144 output_foot_string=''             # 输出文件的底部字符串
145 
146 
147 
148 if   output_type=='xml':
149     output_head_string="<?xml version='1.0' encoding='gb2312'?><proxylist>\n"
150     output_format="""<item>
151             <ip>_ip_</ip>
152             <port>_port_</port>
153             <speed>_speed_</speed>
154             <last_check>_time_checked_</last_check>
155             <area>_area_</area>
156         </item>
157             """
158     output_foot_string="</proxylist>"
159 elif output_type=='htm':
160     output_head_string="""<table border=1 width='100%'>
161         <tr><td>代理</td><td>最后检查</td><td>速度</td><td>地区</td></tr>
162         """
163     output_format="""<tr>
164     <td>_ip_:_port_</td><td>_time_checked_</td><td>_speed_</td><td>_area_</td>
165     </tr>
166     """
167     output_foot_string="</table>"
168 else:
169     output_head_string=''
170     output_foot_string=''
171 
172 if output_type=="csv":
173     output_format="_ip_, _port_, _type_,  _speed_, _time_checked_,  _area_\n"
174 
175 if output_type=="tab":
176     output_format="_ip_\t_port_\t_speed_\t_time_checked_\t_area_\n"
177 
178 if output_type=="txt":
179     output_format="_ip_:_port_\n"
180 
181 
182 # 输出文件的函数
183 def output_file():
184     global output_filename,output_head_string,output_foot_string,output_type
185     if output_type=='':
186         return
187     fnum=len(output_filename)
188     content=[]
189     for i in range(fnum):
190         content.append([output_head_string])
191 
192     conn.execute("select * from `proxier` order by `active`,`type`,`speed` asc")
193     rs=conn.fetchall()
194 
195     for item in rs:
196         type,active=item[2],item[4]
197         if   active is None:
198             content[0].append(formatline(item))   #未检查
199         elif active==0:
200             content[1].append(formatline(item))   #非法的代理
201         elif active==1 and type==2:
202             content[2].append(formatline(item))   #高匿   
203         elif active==1 and type==1:
204             content[3].append(formatline(item))   #普通匿名  
205         elif active==1 and type==0:
206             content[4].append(formatline(item))   #透明代理             
207         elif active==1 and type==-1:
208             content[5].append(formatline(item))   #未知类型的代理
209         else:
210             pass
211 
212     for i in range(fnum):
213         content[i].append(output_foot_string)
214         f=open(output_filename[i]+"."+output_type,'w')
215         f.write(string.join(content[i],''))
216         f.close()
217 
218 #格式化输出每条记录
219 def formatline(item):
220     global output_format
221     arr=['_ip_','_port_','_type_','_status_','_active_',
222         '_time_added_','_time_checked_','_time_used_',
223         '_speed_','_area_']
224     s=output_format
225     for i  in range(len(arr)):
226         s=string.replace(s,arr[i],str(formatitem(item[i],i)))
227     return s
228 
229 
浏览次数:   【 打 印 】【 关 闭
上一篇:C/C++中调用SQLITE3的基本步骤
下一篇:python写的多线程代理服务器(2)
 论坛登陆
用户名:
密  码:
验证码: 
Cookie 选项:
正常登陆 隐身登陆
   
没有注册?
 文章搜索
 推荐文章
 酷站推荐
 热门文章
 网站统计
关于我们 | 网站地图 | 联系我们 | 网站历史 | 友情链接 | TOP
Copyright© 2006 Sqlite中文社区  程序开发: mistletoe  站长: 林轩 陈文成