Я создаю веб-краулер для очистки критических c видеоигр и оценок пользователей от Metacriti c. Я добавляю данные в список видеоигр и их консолей, который у меня уже есть. Естественно, я ожидаю, что некоторые из них не будут работать, поскольку они могут иметь немного разные названия и т. Д. c.
Он работает довольно хорошо, но, похоже, застревает на определенных URL-адресах, ведущих на страницу 404. Иногда он заходит дальше других попыток, что для меня самое странное. Наибольшее значение, которое я получил, составляет где-то около 200. Кажется, что иногда 404-е обрабатываются отлично с обработкой, которую я для него построил, а в других случаях я получаю сообщение об ошибке:
ERROR: Gave up retrying <GET https://www.metacritic.com/game/playstation-4/god-of-war-(2018) (failed 3 times): 504 Gateway Time-out
с любым URL-адресом ошибки 404, который он пытается захватить (я знаю, что могу очистить это «(2018)» и другие подобные вещи позже, но есть некоторые нормальные заголовки, для которых это тоже происходит.
# The gameNumber variable just tells me where in my list of preset video game titles I am, it increases
# with each crawl in order to move to the next game in the list.
gameNumber = 0
class VGSpider(scrapy.Spider):
# Brings in the aforementioned game "lookupList" and the length of that list, so the crawler knows
# when to stop
global lookupList
global finalEntry
name = "mc_spider"
start_urls = ["https://www.metacritic.com/game/" + consoleDict[lookupList[0][1]] + "/" + formatTitle(lookupList[0][2])]
handle_httpstatus_list = [404]
# Here's where we set the logging settings.
custom_settings = {
'LOG_LEVEL': logging.WARNING,
'ITEM_PIPELINES': {'__main__.JsonWriterPipeline': 1}, # This uses the functions in the JsonWriterPipeline class to write the
# Julia file
'FEED_FORMAT':'json', # This sets the feed exporter to export as a JSON file
'FEED_URI': 'mcresult.json', # This simply sets the title for said JSON file
'DOWNLOAD_TIMEOUT' : 180
}
# I added a user agent in case Metacritic was blocking me from scraping
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36'
}
def start_requests(self):
yield Request(self.start_urls[0], headers=self.headers)
def parse(self, response):
global gameNumber
global consoleDict
print(gameNumber)
# Here we declare the selector for each piece of data--this tells scrapy where to check for each item
CRITIC_SCORE_SELECTOR = "//*[@id=\"main\"]/div/div[1]/div[1]/div[3]/div/div/div[2]/div[1]/div[1]/div/div/a/div/span/text()"
CRITIC_REVIEW_COUNT_SELECTOR = "//*[@id=\"main\"]/div/div[1]/div[1]/div[3]/div/div/div[2]/div[1]/div[1]/div/div/div[2]/p/span[2]/a/span/text()"
PLAYERS_SELECTOR = "//*[@id=\"main\"]/div/div[1]/div[1]/div[3]/div/div/div[2]/div[2]/div[2]/ul/li[3]/span[2]/text()"
RELEASEDATE_SELECTOR = "//*[@id=\"main\"]/div/div[1]/div[1]/div[1]/div[3]/ul/li[2]/span[2]/text()"
USER_SCORE_SELECTOR = "//*[@id=\"main\"]/div/div[1]/div[1]/div[3]/div/div/div[2]/div[1]/div[2]/div[1]/div/a/div/text()"
USER_REVIEW_COUNT_SELECTOR = "//*[@id=\"main\"]/div/div[1]/div[1]/div[3]/div/div/div[2]/div[1]/div[2]/div[1]/div/div[2]/p/span[2]/a/text()"
RATING_SELECTOR = "//*[@id=\"main\"]/div/div[1]/div[1]/div[3]/div/div/div[2]/div[2]/div[2]/ul/li[5]/span[2]/text()"
# We check the page--if the page doesn't exist, we fill in the data with NaN values, otherwise we grab them off the page
if (response.status == 404):
yield {
'mc_critic_score' : np.nan,
'mc_critic_count' : np.nan,
'mc_players' : np.nan,
'mc_release_date' : np.nan,
'mc_user_score' : np.nan,
'mc_user_count' : np.nan,
'rating' : np.nan,
'id' : lookupList[gameNumber][0]
}
else:
try:
yield {
'mc_critic_score' : response.xpath(CRITIC_SCORE_SELECTOR).extract(),
'mc_critic_count' : response.xpath(CRITIC_REVIEW_COUNT_SELECTOR).extract(),
'mc_players' : response.xpath(PLAYERS_SELECTOR).extract(),
'mc_release_date' : response.xpath(RELEASEDATE_SELECTOR).extract(),
'mc_user_score' : response.xpath(USER_SCORE_SELECTOR).extract(),
'mc_user_count' : response.xpath(USER_REVIEW_COUNT_SELECTOR).extract(),
'rating' : response.xpath(RATING_SELECTOR).extract(),
'id' : lookupList[gameNumber][0]
}
except:
pass
# Add to the gamenumber and use it to select the information to query the next page
gameNumber += 1
next_page = "https://www.metacritic.com/game/" + consoleDict[lookupList[gameNumber][1]] + "/" + formatTitle(lookupList[gameNumber][2])
if gameNumber == finalEntry:
return
else:
yield scrapy.Request(
response.urljoin(next_page),
callback=self.parse
)