scrapy + selenium: <a>тег не имеет href, но содержимое загружается javascript - PullRequest
0 голосов
/ 12 июля 2020

Я почти готов с первой попытки использовать scrapy, selenium для сбора данных с веб-сайта с javascript загруженным контентом.

Вот мой код:

# -*- coding: utf-8 -*-
import scrapy
from selenium import webdriver
from scrapy.selector import Selector
from scrapy.http import Request
from selenium.webdriver.common.by import By
import time

class FreePlayersSpider(scrapy.Spider):
    name = 'free_players'
    allowed_domains = ['www.forge-db.com']
    start_urls = ['https://www.forge-db.com/fr/fr11/players/?server=fr11']
    driver = {}

    def __init__(self):
        self.driver = webdriver.Chrome('/home/alain/Documents/repository/web/foe-python/chromedriver')
        self.driver.get('https://forge-db.com/fr/fr11/players/?server=fr11')

    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        #time.sleep(1)
        sel = Selector(text = self.driver.page_source)

        players = sel.xpath('.//table/tbody/tr')

        for player in players:
            joueur = player.xpath('.//td[3]/a/text()').get()
            guilde = player.xpath('.//td[4]/a/text()').get()

            yield {
                'player' : joueur,
                'guild' : guilde
            }

        next_page_btn = self.driver.find_element_by_xpath('//a[@class="paginate_button next"]')
       

        if next_page_btn:
            time.sleep(2)
            next_page_btn.click()
            yield scrapy.Request(url = self.start_urls, callback=self.parse)

        # Close the selenium driver, so in fact it closes the testing browser
        self.driver.quit()

    def parse_players(self):
        pass        

I хотите собрать имена пользователей и их относительную гильдию и вывести их в файл csv. На данный момент моя проблема заключается в том, чтобы перейти к СЛЕДУЮЩЕЙ СТРАНИЦЕ и снова проанализировать контент, загруженный javascript.

, если я могу имитировать щелчок по тегу NEXT, я не уверен на 100%, что код будет продолжить все страницы, и я не могу проанализировать новый контент с помощью той же функции.

Есть идеи, как я могу решить эту проблему? спасибо

1 Ответ

0 голосов
/ 12 июля 2020

Вместо использования селена вам следует попробовать заново создать запрос на обновление таблицы. Если присмотреться к HTML под chrometools. Вы можете видеть, что запрос выполняется с параметрами, а ответ отправляется обратно с данными в хорошо структурированном формате.

См. здесь относительно динамического c содержимого в scrapy . Поскольку это объясняет первый шаг, о котором нужно подумать, нужно ли воссоздавать активность браузера? Или я могу получить нужную мне информацию из обратного проектирования HTTP-запросов на получение. Иногда информация скрывается с помощью тегов <script></script>, и вы можете использовать регулярное выражение или некоторые строковые методы, чтобы получить то, что вы хотите. Рендеринг страницы и последующее использование активности браузера следует рассматривать как последний шаг. для реинжиниринга HTTP-запросов.

Обратное проектирование HTTP-запросов в Scrapy

Теперь, с точки зрения самой сети, мы можем использовать chrome devtools, щелкнув правой кнопкой мыши по проверке на странице. Щелкнув вкладку сети, вы можете увидеть все запросы, которые браузер делает для отображения страницы. В этом случае вы хотите увидеть, что произойдет, когда вы нажмете «Далее».

Изображение1: здесь

Здесь вы можете увидеть все запросы, сделанные при нажатии кнопки «Далее» на странице . Я всегда ищу ответ самого большого размера, так как он, скорее всего, будет содержать ваши данные.

Image2: здесь

Здесь вы можете увидеть заголовки / параметры запроса и т.д. c ... вещи, необходимые для правильного HTTP-запроса. Мы видим, что ссылающийся URL-адрес на самом деле является getplayers. php со всеми параметрами для добавления следующей страницы. Если вы прокрутите вниз, вы увидите все те же параметры, которые он отправляет getplayers. php. Имейте это в виду, иногда нам нужно отправить заголовки, файлы cookie и параметры.

Image3: здесь

Вот предварительный просмотр данных, которые мы получим из сервер, если мы сделаем правильный запрос, это хороший аккуратный формат, который отлично подходит для очистки.

Теперь вы можете скопировать заголовки и параметры, файлы cookie сюда в scrapy, но после небольшого поиска и всегда стоит проверить это во-первых, если, просто передав HTTP-запрос с URL-адресом, вы получите нужные данные, тогда это самый простой способ.

В этом случае это правда, и вы получите хороший формат потребности со всеми данные.

Пример кода

import scrapy

class TestSpider(scrapy.Spider):
    name = 'test'
    allowed_domains = ['forge-db.com']
    
    def start_requests(self):
        url = 'https://www.forge-db.com/fr/fr11/getPlayers.php?'
        yield scrapy.Request(url=url)
    def parse(self,response):
        for row in response.json()['data']:
           yield {'name':row[2],'guild':row[3] }

Настройки

В settings.py необходимо указать ROBOTSTXT_OBEY = False Сайт не хочет, чтобы вы получали доступ к этим данным поэтому нам нужно установить его в false. Будьте осторожны, вы можете перестать получать бан на сервере.

Я бы также предложил пару других настроек, чтобы проявить уважение и кэшировать результаты, поэтому, если вы хотите поиграть с этим большим набором данных, не забивайте сервер.

CONCURRENT_REQUESTS = 1
DOWNLOAD_DELAY = 3
HTTPCACHE_ENABLED = True
HTTPCACHE_DIR = 'httpcache'

Комментарии к коду

Мы делаем запрос на https://www.forge-db.com/fr/fr11/getPlayers.php?, и если бы вы распечатали ответ, вы получили бы все данные из таблицы, это довольно лот ... Теперь он выглядит как в формате json, поэтому мы используем новую функцию scrapy для обработки json и преобразования в словарь python. response.json() убедитесь, что у вас есть последняя версия scrapy, чтобы воспользоваться этим. В противном случае вы можете использовать библиотеку json, которую предоставляет python, чтобы сделать то же самое.

Теперь вам нужно посмотреть данные предварительного просмотра abit здесь, но отдельные строки находятся в пределах response.json()['data'][i], где i в строка данных. Имя и гильдия находятся в пределах response.json()['data'][i][2] и response.json()['data'][i][3]. Так что перебираем каждый response.json()['data'] и захватываем имя и гильдию.

Если бы данные не были так структурированы, как здесь, и их нужно было изменить, я настоятельно рекомендую вам использовать Items или ItemLoaders для создания полей что вы можете затем вывести данные. Вы можете легче изменять извлеченные данные с помощью ItemLoaders, и вы можете взаимодействовать с повторяющимися элементами и т. Д. c с помощью конвейера. Это всего лишь некоторые мысли на будущее, я почти никогда не использую дающий словарь для извлечения данных, особенно больших наборов данных.

...