Dawid Loranc „What I cannot create, I do not understand.” - Richard Feynman
We need more data - Scrapy

We need more data - Scrapy

12.03.2017

Ten post jest o rozwijanym przeze mnie bocie do Starcrafta wykorzystującym uczenie maszynowe. Projekt jest rozwijany w ramach konkursu "Daj Się Poznać 2017".


Każdy ambitny gracz Starcrafta 2 wie, że nie wystarczy grać, aby być dobrym. Trzeba, między innymi, analizować swoje gry, a także gry innych, lepszych od nas graczy. Byłoby fajnie gdyby mój bot też coś takiego potrafił przynajmniej w ograniczonym zakresie. Potrzebne mi będą zatem replaye. Skąd je wziąć? Najczęściej bierze się je z takich serwisów jak spawningtool.com albo ggtracker.com, gdzie są publikowane przez graczy. Organizatorzy dużych turniejów także udostępniają paczki z grami profesjonalnych graczy, ale przeszukiwanie internetu, by zdobyć te paczki mnie nie interesuje.

Postanowiłem zatem napisać prosty scrapper przechodzący przez podstrony, wyciągający linki z tabel i pobierający gry z spawningtool.com.

Kod

Najpierw, oczywiście, zainstalowałem Scrapy (później się okazało, że będzie potrzebna także biblioteka requests):

pip install scrapy

Aby zacząć korzystać ze Scrapy można napisać od razu jakiś prosty skrypt i odpalić go używając komendy scrapy runspider <skrypt> albo utworzyć projekt. Ja wybrałem tę drugą opcję i w katalogu głównym projektu wykonałem poniższą komendę:

scrapy startproject replays

Następnie w pliku settings.py ustawiłem pipeline, które umożliwia ściąganie plików, a także ustawiłem ścieżkę do której mają się ściągać pliki:

ITEM_PIPELINES = {
   'scrapy.contrib.pipeline.images.FilesPipeline': 1,
}

FILES_STORE = "./files"

Następnie w pliku items.py stworzyłem prosty model tylko i wyłącznie z polami, które są wymagane, aby Scrapy pobierał pliki:

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class ReplaysItem(scrapy.Item):
    file_urls = scrapy.Field()
    files = scrapy.Field()

W katalogu spiders utworzyłem plik spawning-tool-spider.py o następującej treści:

import scrapy
import requests
from replays.items import ReplayItem


class SpawningToolSpider(scrapy.Spider):
    name = 'spawning-tool-spider'
    # pierwsza strona z replayami, scrapy od czegoś musi zacząć
    start_urls = [
        'http://lotv.spawningtool.com/replays/?p=&query=&after_time=&'
        'before_time=&after_played_on=&before_played_on=&patch=&order_by='
    ]

    # scrapy uruchomiony w konsoli odpala tę metodę i zaczyna scrapować
    def parse(self, response):
        for row in response.css('table tr'):
            # pomijamy pierwszy wiersz tabeli
            if row.css('td:last-child ::attr(href)').extract_first() is None:
                continue
            else:
                url = 'http://lotv.spawningtool.com' \
                    + row.css('td:last-child ::attr(href)').extract_first()

                # typowa ścieżka z plikiem do downloadu to http://lotv.spawningtool.com/<liczba>/download/
                # ale przy pobieraniu następuje przekierowanie 302 do Amazona,
                # więc trzeba było coś z tym zrobić, bo scrapy odmówił posłuszeństwa
                # rozwiązaniem okazało się wyciągnięcie z nagłówków pola Location, czyli właściwego adresu
                request_response = requests.head(url)

                if request_response.status_code == 302:
                    url = request_response.headers["Location"]

                # split, bo scrapy próbował zapisać plik z wartościami pól GET
                # (coś w stylu 322d3a25z2z.SC2Replay?key=0JIDaAJ)
                url = url.split('?')

                # ok, mamy ścieżkę do pliku
                yield ReplayItem(file_urls=[url[0]])

        # przechodzimy do następnej strony
        next_page = response.css('a.pull-right ::attr(href)').extract_first()
        if next_page:
            yield scrapy.Request(response.urljoin(next_page), callback=self.parse)

Następnie wystarczyło odpalić w konsoli komendę:

scrapy crawl spawning-tool-spider

Co dalej?

Na razie jednak dam sobie spokój z próbami przewidzenia co będzie zawierało środowisko od Blizzarda i DeepMind. Replayów nawet nie pobierałem, bo nie wiem czy jest sens. Myślę, że w tym tygodniu spróbuję odtworzyć scenariusze prostego micro z Starcrafta na przeglądarki internetowe i pod to będę pisał przykłady z użyciem sieci neuronowych i reinforcement learningu.

Kategorie: Projekty

Udostępnij: