鱼C论坛

 找回密码
 立即注册
查看: 1948|回复: 11

[原创] python3代理池的搭建(三)

[复制链接]
 楼主| 发表于 2020-5-5 22:08:51 | 显示全部楼层
本帖最后由 十月故里 于 2020-5-6 18:38 编辑

前情回顾~电影里面好像都是这么来的
前面两节分别介绍了构建爬取代理网站的类,和存储代理ip的数据库
没看过的小伙伴可以点击下面的传送门过去看

因为我们的目标是免费的代理ip,所以有很大一部分ip是无效的,要么是刚好被多人用过来爬取目标网站导致被封,所以这一节主要讲解怎么检测这些ip的可用性,同时由于ip数量比较多,这里会用多线程的方法来进行检测
这一节用到的库有sqlite3, time, requests, threading

废话不多说,进入主题,测试ip之前,我们需要把存放在数据库中的ip读取出来,代码如下
lock=threading.Lock()
conn = sqlite3.connect('ip.sqlite')
c = conn.cursor()
cursor = c.execute("select ip,score from ips")
ips = []
for row in cursor:
    ips.append(list(row))
def get_ip():
    lock.acquire()
    if len(ips)==0:
        lock.release()
        return ''
    else:
        proxy=ips[0]
        del ips[0]
    lock.release()
    return proxy
关于从sqlite中读取信息的操作就不细说了,想深入了解的童鞋可以回去看第二节内容里面提到的链接,这里主要说一下threading.Lock(),这是一个线程锁,前面也提到了,我们要采用多线程的方法来检测ip,那么在每个线程读取ip的过程中,不可避免的会出现一个ip多个线程同时读取,或者在读取ip的过程中,其他线程在进行删除ip的操作,导致程序异常,为了避免这个情况,我们用到线程锁来把这个读取ip的操作变成原子操作,当其中一个线程在读取ip的时候,把这个存放IP的ips集合锁起来=》 lock.acquire(),不让别的线程读取,待读取完之后再释放=》 lock.release(),允许别的线程读取ip,这样我们就能避免上述提到的问题的发生了。

接下来我们就开始搭建线程的执行代码了
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
}
update_ips=[]
VALID_STATUS_CODES=[200]
TEST_URL='https://www.baidu.com'
class SpiderThread(threading.Thread):
    def __init__(self,name):
        threading.Thread.__init__(self)
        self.name='thread'+str(name)
    def run(self):
        while True:
            proxy=get_ip()
            try:
                real_proxies = {
                    'http':'http://' + proxy[0],
                    'https':'https://' + proxy[0]
                }
            except Exception:
                break
            if proxy !='':
                try:
                    response=requests.get(url=TEST_URL,headers=headers,proxies=real_proxies,timeout=5)
                    if response.status_code in VALID_STATUS_CODES:
                        proxy[1] = 100
                        update_ips.append(proxy)
                        print('代理可用', proxy[0])
                        time.sleep(5)
                    else:
                        proxy[1] -= 1
                        update_ips.append(proxy)
                        print('请求响应码不合法', proxy[0])
                        time.sleep(5)
                except Exception as e:
                    proxy[1] -= 1
                    update_ips.append(proxy)
                    #print('请求失败',e.args)
            else:
                break
关于请求网站的操作就不细说了,主要说一下这个线程类的框架,分为两部分:
  • 一部分是初始化的'__init__',它继承threading.Thread的基类,里面的self.name是用来定义线程的名字的,不设置就采用默认的格式,thread1 thread2 。。。(没记错的话);
  • 第二部分就是执行方法,它会在线程启动之后自动执行,这里面我们设置了三种情况,有合法响应,有不合法响应,无响应。其中合法响应其实就是上面定义的VALID_STATUS_CODES,一般200就表示网站正常响应请求了,但也有特殊情况,按需添加,而请求的网站放在了TEST_URL中,可以弄成集合,对多个网站测试,看个人需求。这里面能合法响应就把proxy(ip,score)里面的score分值设为100,这个主要是为了后期在读取可用ip的时候用来筛选的,看个人需求可以设置别的,二另外两种情况都给分值减分,当减到0的时候,我们就可以把ip从数据库中剔除(这部分代码还没写),保证数据库的'纯净'。


接下来就是执行线程检测ip可用性,并把得到的新的(ip,score)的集合update_ips从新储存到数据库中
class Tester(object):
    def __init__(self):
        self.threads=[SpiderThread(i) for i in range(1,5)]
    def run(self):
        for threa in self.threads:
            threa.start()
            threa.join()
        for proxy in update_ips:
            #这里必须要用双引号,且ip部分需要用单引号括起来,否则sqlite无法识别多.号的结构,会认为是错误的浮点数格式
            c.execute("update ips set score ={} where ip = '{}'".format(proxy[1], proxy[0]))
        conn.commit()
        conn.close()
第一部分用来初始化线程,range(1,5)有两个含义,一个是定义了4个线程,另一个是每个线程的名字依次为1,2,3,4,这里可以看需求更改,而且线程不是越多越好哈
第二部分就是执行线程的部分,通过.start来启动线程,.join来保证线程运行完才结束,最后再把得到的update_ips刷新到数据库中
if __name__ == '__main__':
    r=Tester()
    r.run()
    conn = sqlite3.connect('ip.sqlite')
    c = conn.cursor()
    ips = c.execute("select ip,score from ips where score>10")
    for ip in ips:
        print(ip)
最后测试一下,运行了一下,发现就5个ip是好使的,其他都gg了,果然免费的就是不好用啊

好了这个系列到此就结束了,欢迎大家批评指正哈
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-5 22:13:43 | 显示全部楼层
@乘号 请@不二
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-5 22:15:42 | 显示全部楼层
十月故里 发表于 2020-5-5 22:08
这个帖子发重了。。。之前一直提示发贴失败,然后多发了一次,不知道怎么删除

加个敏感词,然后标题改成求删帖,应该过不了机器审核
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-5 22:15:54 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-5 23:20:05 | 显示全部楼层
十月故里 发表于 2020-5-5 22:08
这个帖子发重了。。。之前一直提示发贴失败,然后多发了一次,不知道怎么删除

已经帮你删除,这系列文章写的真棒,加油!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-5-5 23:35:27 From FishC Mobile | 显示全部楼层
小甲鱼 发表于 2020-5-5 23:20
已经帮你删除,这系列文章写的真棒,加油!

麻烦小甲鱼了,也感谢甲鱼老司机的捧场
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-6 08:09:29 | 显示全部楼层

为啥你不自己请
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-6 08:10:50 | 显示全部楼层

没好友
请不来
而且现在想加加不了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-5-6 08:40:54 From FishC Mobile | 显示全部楼层
惹,发现我的代码部分内容被吞了,晚点回去补回去
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-5-6 18:42:13 | 显示全部楼层
ok更新回来了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-29 10:14:52 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-22 11:50

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表