前言
在爬取目标网站时采用的多线程操作,理论上速度应该是比串行快很多但是实际效果并没有想象中的那么快,刚开始速度还是可以的,过几个小时以后就慢下来了,重启以后又变快了,这肯定不是网速的原因。
发现问题
我是按照网上的方式使用连接池来连接数据库的
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(), 执行完毕以后就把 cur 和 conn 都断开,实际上只是放到了连接池中,下次调用并非重连,所以理论速度会快很多。
但是我的代理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 个左右,大功告成!