我已经构建了一个程序,可以并行从多个网站抓取数据。我面临的问题是,尽管设置了超时值,我的请求仍经常挂在一个无限循环中而实际上并未执行。
对于每个网站(总共5个),在启动时会创建一个单独的线程,每个线程每分钟调用一次以下功能:
def proxy_request(my_url):
while True: #try request over and over again if it fails for some reason
try:
proxies = {"https": "XXXXXXXX", "http": "XXXXXXX"}
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.73.11 (KHTML, like Gecko) Version/7.0.1 Safari/537.73.11'}
source = requests.get(my_url, proxies=proxies, headers=headers, timeout=5)
return source
break #stop if the request worked out
except(requests.exceptions.SSLError, requests.exceptions.ReadTimeout) as error:
logging.exception("{} {}".format(my_url, datetime.datetime.utcnow()))
print(error)
为了清楚地了解这个问题,我修改了代码:
def proxy_request(my_url):
while True:
try:
proxies = {"http": "XXXXXXXXX", "https":"XXXXXXX"} # Webshare
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36', "Upgrade-Insecure-Requests": "1","DNT": "1","Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Accept-Language": "en-US,en;q=0.5","Accept-Encoding": "gzip, deflate"}
source = requests.get(my_url, proxies=proxies, headers=headers, timeout=10)
return source
break
except Exception as error:
logging.exception("{} {}".format(my_url, datetime.datetime.utcnow()))
print(error)
finally:
print(my_url[0:30], "Request completed")
finally永远不会对不成功的请求执行,不会引发任何错误,未完成的请求永远不会出现在日志文件中,只有成功的请求才会这样做。因此,我认为确实是请求本身挂在无限循环中。
我最初的想法是网站必须有适当的保护措施,以防止人们抓取数据。造成这种情况的原因在于,连续多次(始终使用相同的代理设置)重新启动脚本通常可以解决此问题。这是不可预测的,哪个站点在每次启动时都可以正常工作,最多需要10个重新启动,直到有相当数量的站点才能正常工作,但是,如果站点从一开始就可以正常运行,则通常需要很长时间(对它进行测试)超过24小时)。我对所有请求都使用相同的代理,并且在重新启动期间不更改它。
如何才能更清楚地诊断请求为何被挂起?
经过一定时间后杀死请求的最优雅方法是什么?
我尝试使用eventlet来执行此操作(如建议的here),但是它导致“ RecursionError:超出最大递归深度”。我不能使用信号,因为我希望我的代码可以在Windows和Linux上运行。
谢谢!