Python 多线程爬虫连接池 PooledDB

前言

在爬取目标网站时采用的多线程操作,理论上速度应该是比串行快很多但是实际效果并没有想象中的那么快,刚开始速度还是可以的,过几个小时以后就慢下来了,重启以后又变快了,这肯定不是网速的原因。

发现问题

我是按照网上的方式使用连接池来连接数据库的

import pymysql
from DBUtils.PooledDB import PooledDB
pool = PooledDB(pymysql,5,host='localhost',user='root',passwd='pwd',db='myDB',port=3306) #5为连接池里的最少连接数

 
conn = pool.connection()  #以后每次需要数据库连接就是用connection()函数获取连接就好了
cur=conn.cursor()
SQL="select * from table1"
r=cur.execute(SQL)
r=cur.fetchall()
cur.close()
conn.close()

每次执行语句的时候都是用 pool.connection(), 执行完毕以后就把 curconn 都断开,实际上只是放到了连接池中,下次调用并非重连,所以理论速度会快很多。

但是我的代理IP是放到了另一个文件中,使用的调用函数从数据库中取 IP ,当时以为这个操作不是很频繁,就没有用代理池,用的最古老的 pymysql 连接,在100个线程中都创建了一个 conn 对象,导致不知什么原因这些连接全部都处于sleep状态,而且100个线程竟然又200多个 mysql 连接!!不能忍了,这应该才是爬虫速度变慢的原因。

于是改了一下策略

from crawl_xici_ip import GetIP
class CaiJiThread(threading.Thread):
    def __init__(self, thread_id, name):
        threading.Thread.__init__(self)
        self.p = GetIP()


    # 随机从配置文件里选择一条IP:PORT
    def ip_choice_one(self):
        http = self.p.get_random_ip(pool)
        self.proxies_random = {
            "http": http,
            # "https": http_ip,
        }

if __name__ == "__main__":
    pool = PooledDB(pymysql,5,host='localhost',user='root',passwd='pwd',db='myDB',port=3306)

这样每次调用的时候都把 pool 传给 get_random_ip(pool)

class GetIP(object):

    def judge_ip(self, ip, port, pool):
        #判断ip是否可用
        http_url = "测试网址"
        proxy_url = "http://{0}:{1}".format(ip, port)
        headers = {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML,'
                          ' like Gecko) Chrome/55.0.2883.95 Safari/537.36',

        }
        try:
            proxy_dict = {
                "http":proxy_url,
            }
            response = requests.get(http_url, headers=headers, proxies=proxy_dict)
        except Exception as e:
            # print("invalid ip and port")
            self.delete_ip(ip, port, pool)
            return False
        else:
            code = response.status_code
            if code >= 200 and code < 300:
                # print("effective ip")
                return True
            else:
                # print("invalid ip and port")
                self.delete_ip(ip, port, pool)
                return False

    def get_random_ip(self, pool):

        #从数据库中随机获取一个可用的ip
        conn = pool.connection()
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        random_sql = """
              SELECT ip, port FROM ip_proxies 
            ORDER BY created_time desc LIMIT 100;
            """
        cursor.execute(random_sql)
        result = random.choice(cursor.fetchall())

        ip = result['ip']
        port = result['port']
        # print(ip,port)
        judge_re = self.judge_ip(ip, port, pool)
        if judge_re:
            # print("http://{0}:{1}".format(ip, port))
            cursor.close()
            conn.close()
            return "http://{0}:{1}".format(ip, port)
        else:
            return self.get_random_ip(pool)

    def delete_ip(self,ip, port, pool):
        conn = pool.connection()
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        sql = """DELETE FROM ip_proxies WHERE ip='%s' and port='%s';"""
        data = (ip, port)
        cursor.execute(sql % data)
        conn.commit()
        cursor.close()
        conn.close()

最终发现那些 sleep 的连接都没了,而且连接也恢复到了 100 个左右,大功告成!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值