google-app-engine - GAE gunicorn flask 处理需要 30-60 分钟的请求的最佳方式
问题描述
我用烧瓶构建了一个应用程序,它应该能够爬取一些数据。第一步是使用 Youtube Data API 获取有关用户的一些数据,包括用户上传的所有视频的列表。这完全可以正常工作!在获得视频 ID 列表后,我尝试在 youtube 上抓取所有这些视频,以提取所有视频的点赞数和观看次数,并将它们加起来为 2 个大数字。我在没有 gunicorn 的情况下在本地测试它,而不是在应用程序引擎中,它工作正常!但是当用户上传 6700 个视频时,可能需要 30 分钟才能完成请求(本地有效)。 当我尝试在 GAE 中运行相同的代码时,它会在几分钟后返回 502 Bad Gateway,但在日志中我看到它仍在爬行。这是 GET 502:
这是我编写的爬取代码:这是我的 app.yaml。使用 -t 36000 Worker 可以静默一小时,直到它们被杀死并重新启动。
runtime: python37
service: crawler
entrypoint: . ./env.inc.sh && gunicorn -t 36000 -b :$PORT app:app
这是我的 app.py 中的路由,称为:
@app.route('/youtube/username/<user>')
def youtubeStatistics(user):
response = crawler.crawl_youtube_user(os.environ['YOUTUBE_API_KEY'], user)
if response:
return jsonify(response), 200
else:
return jsonify({"prettyMessage": "Quota Limit maybe Exceeded"}), 403
这些是我使用的爬虫功能:
def scrape_url(url):
r = requests.get(url)
page = r.text
soup = bs(page, 'html.parser')
return soup
def crawl_youtube_user(KEY, username):
youtube = set_up(KEY)
request = youtube.channels().list(
part="snippet,contentDetails,statistics",
forUsername=username
)
uploadPlaylistId = ""
data = {}
try:
response = request.execute()
except:
return {}
if (response["pageInfo"]["totalResults"] > 0):
stats = response["items"][0]["statistics"]
data["subscriberCount"] = stats["subscriberCount"]
data["videoCount"] = stats["videoCount"]
data["publishedAt"] = response["items"][0]["snippet"]["publishedAt"]
uploadPlaylistId = response["items"][0]["contentDetails"]["relatedPlaylists"]["uploads"]
request = youtube.playlistItems().list(
part="snippet,contentDetails",
maxResults=50,
playlistId=uploadPlaylistId
)
videoIds = []
while True:
try:
response = request.execute()
except:
return {}
for vid in response["items"]:
videoIds.append(vid["snippet"]["resourceId"]["videoId"])
if "nextPageToken" not in response:
break
else:
request = youtube.playlistItems().list(
part="snippet,contentDetails",
maxResults=50,
playlistId=uploadPlaylistId,
pageToken=response["nextPageToken"]
)
data.update(crawl_youtube_videos(videoIds))
return data
def crawl_youtube_videos(ids):
data = {'viewCount': 0, 'videoLikes': 0}
counter = 0
idlength = len(ids)
for id in ids:
counter += 1
print('{}/{}: Scraping Youtube videoId {}'.format(counter,idlength,id))
soup = scrape_url('https://www.youtube.com/watch?v={}&gl=DE&hl=de'.format(id))
try:
data['viewCount'] += int(soup.find('div', class_='watch-view-count').getText().split(' ')[0].replace('.', '').replace(',', ''))
except:
print("Error while trying to extract the views of a Video: {}.".format(sys.exc_info()[0]))
try:
data['videoLikes'] += int(soup.find("button",{"title": "Mag ich"}).find("span").getText().replace('.', '').replace(',', ''))
except:
print("Error while trying to extract the likes of a Video: {}.".format(sys.exc_info()[0]))
return data
我不想使用更多线程或类似的东西,以使整个过程更快!如果我在短时间内爬到许多网站,我害怕我的 IP 被阻止或类似的事情。我只是尝试让请求保持有效,直到我得到我想要的响应。那么是否有更多机制可以保护 GAE-App 免受长响应时间或类似的影响?处理需要 30-60 分钟的请求的最佳方式是什么?
解决方案
推荐阅读
- python - 如何在python中的块中进行循环
- go - 如何正确使用同步机制从串口读取输入
- node.js - 将代码推送到 git repo 后,npm audit fix 所做的更改是否仍然存在?
- swift - 使用空变量初始化结构并使其全局可用
- ios - Dropbox 迁移(API v1 已停用)iOS 目标 c(备份、恢复)
- jquery - 使用 jQuery 的实时消息
- css - Angular 版本 5,引导程序
- c# - .NET UIElement.TranslatePoint 的 UWP 等效项
- python - django.db.utils.OperationalError:(1052,“字段列表中的列'名称'不明确”)
- testing - Protractor Vs Suitest vs Cypress 哪个框架更适合大型角度应用程序?