我们可以使用以下几个方法来增强,下载的稳定性
-
代理 一些收费的代理提高下载的稳定性。包括一些很难被采集的数据,通过代理使用个人IP,可以极大的简化下载的这个过程。这是很重要的一点。
-
队列 采集是一个比较耗时的过程,所以在这个时候需要使用队列,比如python里的Celery。使用队列的话可以对采集任务进行排队,已实现异步采集。
-
重试 我们需要使用重试。重试可以在任务没有达到预期的目标的时候,Celery里有自动重试的机制,我们也可以自己手动的增加某些重试逻辑。这样的话,内容可能第一次采集不下来,但是三次之内它的被采集下来的概率可能很大,或者我们可以放大到五次,十次,这个可以极大的提高获取内容的概率。
-
通知 我们需要为每一次采集增加通知,这样我们就可以知道哪些成功了,哪些没有成功。我们可以对于没有成功的采集进行重试。
-
自动重试 我们可以同时增加另外一个脚本,这个脚本每隔一段时间重新去检查所有的采集任务的状态,它就会自动触发所有失败的采集。这样的话可以避免在某个时间点采集不下来,换个时间点就行了。
以下是Celery的主要逻辑,包括通知和自动重试
import requests
import json
import logging
import pymysql
import logging
from DB import DB
from review_crawler import ReviewCrawler
from datetime import datetime
from typing import List
from celery import Celery
from review_crawler import ReviewCrawler
from pymysql.converters import escape_string
logging.basicConfig(filename='crawler.log', level=logging.INFO)
app = Celery('tasks', broker='redis://localhost:6379/0')
db = DB()
@app.task(bind=True, max_retries=2)
def run_tasks(self, data):
try:
q_url = data['q_url']
prompts = data['prompts']
session_id = data['session_id']
logging.info(f"Crawler started for URL: {q_url}, Session ID: {session_id}")
reviewCrawler = ReviewCrawler()
reviews,product_title = reviewCrawler.getReviews(q_url)
logging.info(reviews)
if reviews:
saveReviews(data, reviews)
else:
updateQuestionState(session_id, 3)
message = f"Task succeeded for URL: {q_url}, Session ID: {session_id}. No Review."
send_slack_notification(message)
return {"error": "no Review"}
question = mergeQuestion(reviews, prompts)
if question:
updateQuestion(session_id, question,product_title)
else:
return {"error": "updateQuestion error"}
logging.info(f"Task succeeded for URL: {q_url}, Session ID: {session_id}")
message = f"Task succeeded for URL: {q_url}, Session ID: {session_id}"
send_slack_notification(message)
return getQuestion(session_id)
except Exception as exc:
logging.error("Task failed: %s", exc)
if self.request.retries == 2: # Check if it's the third retry
message = f"Task failed for URL: {q_url}, Session ID: {session_id} after 3 retries. Click here to retry: https://xxxxx={session_id}"
send_slack_notification(message)
else:
message = f"Task failed for URL: {q_url}, Session ID: {session_id}. Retrying... {self.request.retries+1}"
send_slack_notification(message)
raise self.retry(exc=exc, countdown=10)
def send_slack_notification(message):
try:
webhook_url = 'xxx'
data = {
'text': message,
'username': 'research_api',
'icon_emoji': ':frog:'
}
requests.post(webhook_url, data=json.dumps(data), headers={'Content-Type': 'application/json'})
except Exception as e:
logging.error(f"Error sending Slack notification: {e}")