#python #google-cloud-platform #google-cloud-functions
#python #google-облачная платформа #google-cloud-функции
Вопрос:
У меня есть облачная функция, код работает нормально, когда я тестирую локально. Однако она не работает как облачная функция, даже несмотря на успешное развертывание. При развертывании я попытался добавить allUsers в качестве средства вызова облачной функции. Параметры входа настроены так, чтобы разрешать весь веб-трафик.
Я получаю ошибку 500, и в ней говорится> Ошибка: не удалось обработать запрос при посещении URL.
Облачный планировщик постоянно выходит из строя, и журналы для облачной функции на самом деле не помогают понять, почему она выходит из строя.
При расширении журналы также не содержат дополнительных подробностей.
Я понятия не имею, что еще можно попробовать и решить эту проблему. Я просто хочу иметь возможность вызывать мою облачную функцию HTTP по расписанию, код отлично работает при запуске и тестировании с использованием учетной записи службы. Почему она не работает при добавлении в функцию?
Вот код, который я использую;
from bs4 import BeautifulSoup
import pandas as pd
import constants as const
from google.cloud import storage
import os
import json
from datetime import datetime
from google.cloud import bigquery
import re
from flask import escape
#service_account_path = os.path.join("/Users/nbamodel/nba-data-keys.json")
#os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = service_account_path
client = storage.Client()
bucket = client.get_bucket(const.destination_gcs_bucket)
def scrape_team_data(request):
"""HTTP Cloud Function.
Args:
request (flask.Request): The request object.
<http://flask.pocoo.org/docs/1.0/api/#flask.Request>
Returns:
The response text, or any set of values that can be turned into a
Response object using `make_response`
<http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
"""
headers = [
'Rank',
'Team',
'Age',
'Wins',
'Losses',
'PW',
'PL',
'MOV',
'SOS',
'SRS',
'ORtg',
'DRtg',
'NRtg',
'Pace',
'FTr',
'_3PAr',
'TS_pct',
'offense_eFG_pct',
'offense_TOV_pct',
'offense_ORB_pct',
'offense_FT_FGA',
'defense_eFG_pct',
'defense_TOV_pct',
'defense_DRB_pct',
'defense_FT_FGA',
'Arena',
'Attendance',
'Attendance_Game'
]
r = requests.get('https://www.basketball-reference.com/leagues/NBA_2020.html')
matches = re.findall(r'id="misc_stats". ?(?=table>)table>', r.text, re.DOTALL)
find_table = pd.read_html('<table ' matches[0])
df = find_table[0]
df.columns = headers
filename = 'teams_data_adv_stats' # datetime.now().strftime("%Y%m%d")
df.to_json(filename, orient='records', lines=True)
print(filename)
# Push data to GCS
blob = bucket.blob(filename)
blob.upload_from_filename(
filename=filename,
content_type='application/json'
)
# Create BQ table from data in bucket
client = bigquery.Client()
dataset_id = 'nba_model'
dataset_ref = client.dataset(dataset_id)
job_config = bigquery.LoadJobConfig()
job_config.create_disposition = 'CREATE_IF_NEEDED'
job_config.source_format = bigquery.SourceFormat.NEWLINE_DELIMITED_JSON
uri = "gs://nba_teams_data/{}".format(filename)
load_job = client.load_table_from_uri(
uri,
dataset_ref.table("teams_data"),
location="US", # Location must match that of the destination dataset.
job_config=job_config,
) # API request
print("Starting job {}".format(load_job.job_id))
load_job.result() # Waits for table load to complete.
print("Job finished.")
destination_table = client.get_table(dataset_ref.table("teams_data"))
print("Loaded {} rows.".format(destination_table.num_rows))
return
Комментарии:
1. Ошибка 500 обычно означает сбой вашего кода. Посмотрите в Stackdriver для вашей функции более подробную информацию.
Ответ №1:
Я внедрил ваш код в облачную функцию, и она не работает по двум причинам.
Во-первых, в ней отсутствует requests
зависимость, поэтому строка import requests
должна быть добавлена поверх файла вместе с другими импортируемыми файлами.
Во-вторых, похоже, что ваш код пытается записать файл в файловую систему, доступную только для чтения, которая немедленно отклоняется ОС, и функция завершается. Указанная операция записи выполняется методом DataFrame.to_json
, который пытается записать содержимое в файл teams_data_adv_stats
, чтобы позже загрузить его в корзину GCS.
Есть два способа обойти эту проблему:
-
Создайте файл во временной папке. Как объясняется в документации, вы не можете выполнять запись в файловой системе, за исключением
/tmp
каталога. Мне удалось добиться успеха, используя этот метод со следующими измененными строками:filename = 'teams_data_adv_stats' path = os.path.join('/tmp', filename) df.to_json(path, orient='records', lines=True) blob = bucket.blob(filename) blob.upload_from_filename( filename=path, content_type='application/json' )
-
Избегайте создания файла и работайте со строкой. Вместо использования
upload_from_filename
я предлагаю вам поработать сupload_from_string
. Мне удалось добиться успеха, используя этот метод со следующими измененными строками:filename = 'teams_data_adv_stats' data_json = df.to_json(orient='records', lines=True) blob = bucket.blob(filename) blob.upload_from_string( data_json, content_type='application/json' )
Предупреждаю, вы можете протестировать свои облачные функции на вкладке тестирование в разделе Сведения о функции. Я рекомендую вам использовать его, потому что это то, с чем я работал для устранения вашей проблемы, и может быть полезно узнать об этом. Также имейте в виду, что существует постоянная проблема с журналами сбоев облачных функций во время выполнения python37, которая предотвращает появление сообщения об ошибке. Я столкнулся с проблемой во время работы над вашим CF и решил ее с помощью предоставленного обходного пути.
В качестве дополнительного примечания я сделал все воспроизведение со следующим requirements.txt
файлом, чтобы успешно развернуть и запустить, поскольку вы его не предоставили. Я предполагаю, что это правильно:
beautifulsoup4==4.9.1
Flask==1.1.2
google-cloud-bigquery==1.27.2
google-cloud-storage==1.30.0
lxml==4.5.2
pandas==1.1.1
Комментарии:
1. Спасибо за это! Проблема решена полностью!