问题:
在使用代理IP爬取数据的时候,经常会出现爬取的网址信息不完整的现象。其中有个原因就是timeout设置问题。
代码如下:
import requests
from bs4 import BeautifulSoup
import chardet
import re
import random
import getIPa_from_rds
from datetime import *
import pymysql
#抽取IP地址
proxies_list = getIPa_from_rds.get_Ip(20000) # 从数据库内导入IP地址 可选择数量
print('导出的代理IP的数量:',len(proxies_list))
USER_AGENTS = [
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60',
'Opera/8.0 (Windows NT 5.1; U; en)',
'Mozilla/5.0 (Windows NT 5.1; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.50',
'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.50',
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0',
'Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER',
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)',
'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 SE 2.X MetaSr 1.0',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 UBrowser/4.0.3214.0 Safari/537.36'
]
url = 'http://list.secoo.com/bags/30-0-0-0-0-1-0-0-1-10-0-0.shtml#pageTitle'
code = 0
while code <200:
proxies = {'https': random.choice(proxies_list), #随机选取代理IP
'http': random.choice(proxies_list)}
headers = {
'user-agent': random.choice(USER_AGENTS)} #随机选取代理的AGENT
try:
response = requests.get(url=url, headers=headers,proxies=proxies,timeout=(1))
print(response.text)
response.encoding = chardet.detect(response.content)['encoding']
text = response.text
soup = BeautifulSoup(text, 'lxml')
new_url_list = soup.find_all('a', href=re.compile('source=list'), id=re.compile('name'))
for i in new_url_list:
print(i.get('href'))
if len(new_url_list) > 39:
code = 300
else:
code = 3
print(code, '网页连接成功,但是未爬取完整的数据,重新开始爬取数据')
except:
code = 2
print('IP无效','code等于',code)
conn= pymysql.connect(host='rm-bp1w1p1b35c3g17caeo.mysql.rds.aliyuncs.com', user='evan_wang',password='Evanjunhui', db ='spider',port=3306, charset='utf8')
print('连接数据库成功!')
cursor = conn.cursor()
for i in new_url_list:
time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
secoo_item_url = i.get('href')
sql = '''insert into secoo_url_list (iterm_url,crawl_time)
values ('%s','%s')''' %(secoo_item_url,time) # ''' ''' 一定要使用,不然会出现解析失败
try:
cursor.execute(sql)
conn.commit()
print('数据写入成功')
except:
cursor.rollback()
print('写入失败')
cursor.close()
conn.close()
运行结果如下:
代码中我编写了下面代码,来识别,是否抓取完整的网页代码。如果没有继续抓取。那么问题出在哪里呢?
if len(new_url_list) > 39:
code = 300
else:
code = 3
print(code, '网页连接成功,但是未爬取完整的数据,重新开始爬取数据')
问题在,我在这段中设置的timeout的时间为1,(如果对requests 中的 timeout 不了解,请到滑到博客底部)。
意味着‘连接到服务器的时间’加上‘读取服务器传过来信息的时间’ 合计为1秒。 那么假设,我花了0.5秒得到服务器的响应,但是我需要5秒才能加载成功,那么我只能得到大概15%的信息。所以必然未出现,大量的数据遗漏。 那么我现在把 timeout的设置改为如下,等待服务器的响应时间为1秒,接收信息的时间为10秒。
response = requests.get(url=url, headers=headers,proxies=proxies,timeout=(1,10))
结果如下:成功读取完整信息,并且爬取下来。
注意:timeout 设置只是一个爬取网页信息不完整的其中一个原因。
基础知识:
引用(http://2.python-requests.org/zh_CN/latest/user/advanced.html#timeout)
为防止服务器不能及时响应,大部分发至外部服务器的请求都应该带着 timeout 参数。在默认情况下,除非显式指定了 timeout 值,requests 是不会自动进行超时处理的。如果没有 timeout,你的代码可能会挂起若干分钟甚至更长时间。
连接超时指的是在你的客户端实现到远端机器端口的连接时(对应的是`connect()`_),Request 会等待的秒数。一个很好的实践方法是把连接超时设为比 3 的倍数略大的一个数值,因为 TCP 数据包重传窗口 (TCP packet retransmission window) 的默认大小是 3。
一旦你的客户端连接到了服务器并且发送了 HTTP 请求,读取超时指的就是客户端等待服务器发送请求的时间。(特定地,它指的是客户端要等待服务器发送字节之间的时间。在 99.9% 的情况下这指的是服务器发送第一个字节之前的时间)。
如果你制订了一个单一的值作为 timeout,如下所示:
r = requests.get('https://github.com', timeout=5)
这一 timeout 值将会用作 connect
和 read
二者的 timeout。如果要分别制定,就传入一个元组:
r = requests.get('https://github.com', timeout=(3.05, 27))
如果远端服务器很慢,你可以让 Request 永远等待,传入一个 None 作为 timeout 值,然后就冲咖啡去吧。
r = requests.get('https://github.com', timeout=None)