Scrapy爬取美女图片第三集 代理ip(下)



这是我的公众号获取原创保护的首篇文章,原创的肯定将支持我继续前行。现在写这篇文章的时间是晚上11:30,写完就回寝室休息了,希望更多的朋友与我一起同行(当然需要一个善良的妹子的救济)。

      好了,废话不多说,咱们进入今天的主题。上一篇咱们讲解了代理ip上篇,本篇咱们继续讲解代理ip。这一篇是上一篇的扩展优化,主要的改动是使用scrapy来进行爬取代理ip,同时演示在scrapy框架中怎么使用mongodb数据库,最后使用多线程批量验证代理ip的合理性,大大加快了速度。

 

 

  这次我选择的依然是http://www.xicidaili.com/nn/,我之后打算做一个大的代理ip池,方便之后做分布式爬虫

 

 

   使用firebug审查元素,查看如何解析html,上一篇我已经讲过了,所以就不详细说了,大家不明白的可以看看代理ip上篇

 

      下面咱们可以写代码了,由于咱们使用的是scrapy框架进行爬取,所以首先先生成scrapy工程,在cmd中 输入scrapy startproject proxySpider_scrapy,然后使用pycharm打开。

 

工程结构如下:

 

  db包中db_helper:实现的是mongodb的增删改查。和代理ip上篇增加了proxyId字段

 

  detect包中 detect_proxy:验证代理ip的可用性的线程

                    detect_manager: 用来管理验证线程,监控线程状态

 

  spiders包中 proxySpider:主要实现爬虫的逻辑和html解析

 

  items:主要是描述了ip和port

 

  pipelines:里面主要是将爬取到的ip和port存储到数据库中

 

  main:主要是完成参数的判断和爬虫的启动(咱们使用脚本来启动爬虫不使用命令行)

 

 

        还要说一下检测:我是用 http://ip.chinaz.com/getip.aspx作为检测网址,只要使用代理访问不超时,而且响应码为200,咱们就认为是成功的代理。

 

 

 

  接下来运行程序看看效果:

  在windows下切换到工程目录,运行python main.py -h,会看到我定义的使用说明和参数设置。和上一篇基本上完全一样。

 

 

  接着运行python main.py -c 1 5  (意思是爬取1-5页的ip地址):

 

 

  这时候如果想验证ip的正确性:运行python main.py -t db

 

 

  使用多线程验证的速度非常快,我设置了5个线程。两分钟不到,就验证结束。124个ip是可以使用的。

 

 

  看一下mongodb数据库:

 

 

   大家注意到那个proxyId字段了吗?这个在我们进行多线程分段验证的时候是很有用的。详细的使用,请看代码。

 

 

       当咱们下一篇讲解突破反爬虫的时候就可以使用这些ip了。

 

 

 下面把解析和验证的代码贴一下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
proxySpider.py:
#coding:utf-8
import   scrapy
from   proxySpider_scrapy.db.db_helper  import   DB_Helper
from   proxySpider_scrapy.detect.detect_proxy  import   Detect_Proxy
from   proxySpider_scrapy.detect.detect_manager  import   Detect_Manager
from   proxySpider_scrapy.items  import   ProxyItem
 
 
'''
这个类的作用是将代理数据进行爬取
'''
class   ProxySpider(scrapy.Spider):
     name  =   'proxy'
     start_urls  =   [ "http://www.xicidaili.com/nn/" ]
     allowed_domains  =   []
     db_helper  =   DB_Helper()
     detecter  =   Detect_Manager( 5 )
     Page_Start  =   1
     Page_End  =   4
     headers  =   {
          'Accept' 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' ,
         'Accept-Language' 'en' ,
         'Referer' : 'http://www.xicidaili.com/'
     }
 
     def   parse( self , response):
         '''
         解析出其中的ip和端口
         :param response:
         :return:
         '''
         trs  =   response.xpath( '//tr[@class="odd" or @class=""]' )
         for   tr  in   trs:
             item  =   ProxyItem()
             tds  =   tr.xpath( './td/text()' ).extract()
             for   td  in   tds:
                 content  =   td.strip()
                 if   len (content)> 0 :
                     if   content.isdigit():
                         item[ 'port' =   content
                         print   'ip:' ,item[ 'ip' ]
                         print   'port:' ,item[ 'port' ]
                         break
                     if   content.find( '.' )! =   - 1 :
                         item[ 'ip' =   content
 
 
             yield   item
         if   self .Page_Start <  self .Page_End:
             new_url  =   self .start_urls[ 0 ] + str ( self .Page_Start)
             self .Page_Start  + =   1
             yield   scrapy.Request(new_url,headers = self .headers,callback = self .parse)

  

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
pipelines.py:
# -*- coding: utf-8 -*-
 
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
 
from   proxySpider_scrapy.spiders.proxySpider  import   ProxySpider
 
 
class   ProxyPipeline( object ):
     proxyId  =   1   #设置一个ID号,方便多线程验证
     def   process_item( self , item, spider):
         '''
 
         :param item:
         :param spider:
         :return:
         '''
         if   spider.name  = =   'proxy' : #需要判断是哪个爬虫
 
             proxySpider  =   ProxySpider(spider)
             proxy  =   { 'ip' :item[ 'ip' ], 'port' :item[ 'port' ]}
             proxy_all  =   { 'ip' :item[ 'ip' ], 'port' :item[ 'port' ], 'proxyId' : self .proxyId}
             if   proxySpider.db_helper.insert(proxy,proxy_all)  = =   True : #插入数据
                  self .proxyId  + =   1
             return   item
 
         else :
             return   item

  

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
detect_manager.py:
#coding:utf-8
from   threading  import   Thread
import   time
 
from   proxySpider_scrapy.db.db_helper  import   DB_Helper
from   proxySpider_scrapy.detect.detect_proxy  import   Detect_Proxy
 
'''
定义一个管理线程,来管理产生的线程
'''
class   Detect_Manager(Thread):
 
     def   __init__( self ,threadSum):
         Thread.__init__( self )
         sqldb  =   DB_Helper() #将序号重新恢复
         sqldb.updateID()
         self .pool  = []
         for   in   range (threadSum):
             self .pool.append(Detect_Proxy(DB_Helper(),i + 1 ,threadSum))
 
 
     def   run( self ):
         self .startManager()
         self .checkState()
 
     def   startManager( self ):
         for   thread  in   self .pool:
             thread.start()
 
     def   checkState( self ):
         '''
         这个函数是用来检测线程的状态
         :return:
         '''
         now  =   0
         while   now <  len ( self .pool):
             for   thread  in   self .pool:
                 if   thread.isAlive():
                     now  =   0
                     break
                 else :
                     now + = 1
             time.sleep( 0.1 )
         goodNum = 0
         badNum  = 0
         for   in   self .pool:
 
             goodNum  + =   i.goodNum
             badNum  + =   i.badNum
         sqldb  =   DB_Helper() #将序号重新恢复
         sqldb.updateID()
         print   'proxy good Num ---' ,goodNum
         print   'proxy bad Num ---' ,badNum

  

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
detect_proxy.py:
#coding:utf-8
import   socket
from   threading  import   Thread
 
import   urllib
 
'''
这个类主要是用来检测代理的可用性
'''
class   Detect_Proxy(Thread):
 
 
     url  =   'http://ip.chinaz.com/getip.aspx'
     def   __init__( self ,db_helper,part, sum ):
         Thread.__init__( self )
         self .db_helper  =   db_helper
         self .part  =   part #检测的分区
         self . sum   =   sum #检索的总区域
 
         self .counts  =   self .db_helper.proxys.count()
         socket.setdefaulttimeout( 2 )
         self .__goodNum  =   0
         self .__badNum  =   0
 
     @property
     def   goodNum( self ):
         return   self .__goodNum
 
     @goodNum .setter
     def   goodNum( self ,value):
         self .__goodNum  =   value
 
     @property
     def   badNum( self ):
         return   self .__badNum
 
 
     @badNum .setter
     def   badNum( self ,value):
         self .__badNum  =   value
 
 
     def   run( self ):
 
         self .detect() #开始检测
 
 
     def   detect( self ):
         '''
         http://ip.chinaz.com/getip.aspx  作为检测目标
         :return:
         '''
 
         if   self .counts <  self . sum :
             return
 
         pre  =   self .counts / self . sum
         start  =   pre  *   ( self .part - 1 )
         end  =   pre  *   self .part
         if   self .part  = =   self . sum : #如果是最后一部分,结束就是末尾
             end  =   self .counts
         # print 'pre-%d-start-%d-end-%d'%(pre,start,end)
 
         proxys  =   self .db_helper.proxys.find({ 'proxyId' :{ '$gt' :start, '$lte' :end}}) #大于start小于等于end,很重要
 
 
         for   proxy  in   proxys:
 
             ip  =   proxy[ 'ip' ]
             port  =   proxy[ 'port' ]
             try :
                 proxy_host  = "http://ha:ha@" + ip + ':' + port  #随便添加了账户名和密码,只是为了防止填写账户名密码暂停的情况
                 response  =   urllib.urlopen( self .url,proxies = { "http" :proxy_host})
                 if   response.getcode()! = 200 :
                     self .db_helper.delete({ 'ip' :ip, 'port' :port})
                     self .__badNum  + =   1
                     print   proxy_host, 'bad proxy'
                 else :
                     self .__goodNum  + =   1
                     print   proxy_host, 'success proxy'
 
             except   Exception,e:
                 print   proxy_host, 'bad proxy'
                 self .db_helper.delete({ 'ip' :ip, 'port' :port})
                 self .__badNum  + =   1
                 continue

  

完整的代码我已经上传到github上:
https://github.com/qiyeboy/proxySpider_scrapy


今天的分享就到这里,已经晚上12:15了,如果大家觉得还可以呀,请继续支持我。提前透露一下,下一篇会讲解突破反爬虫

 

  欢迎大家支持我公众号:    

 

本文章属于原创作品,欢迎大家转载分享。尊重原创,转载请注明来自:七夜 http://blog.csdn.net/qiye_/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值