Парсинг сайта fightmatrix с помощью Python и Scrapy | Блог python программиста
Изображение гика

Блог питониста

Парсинг сайта fightmatrix с помощью Python и Scrapy

10 мая 2022 г.

Одна из часто встречающихся задач - парсинг каких-либо сайтов. Для этой цели удобно использовать фреймворк Scrapy. Парсить буду сайт fightmatrix.com.

Как подготовить проект и попробовать его запустить:

pip install scrapy
scrapy startproject fightmatrix
cd fightmatrix/
scrapy genspider fightmatrix_spider fightmatrix.com
scrapy crawl fightmatrix_spider

Здесь я ставлю scrapy, создаю новый проект, перехожу в папку с проектом и создаю паука. Паук создается в папке fightmatrix/spiders/fightmatrix_spider.py:

 1import scrapy
 2from fightmatrix.items import FightmatrixItem
 3
 4
 5class FightmatrixSpider(scrapy.Spider):
 6    name = 'fightmatrix_spider'
 7    allowed_domains = ['fightmatrix.com']
 8    start_urls = ['http://fightmatrix.com/']
 9
10    def parse(self, response):
11        pass

в папке fightmatrix/items.py создается наш конечный класс, используя который мы будем парсить сайт. Сразу пропишу некоторые поля:

1import scrapy
2
3
4class FightmatrixItem(scrapy.Item):
5    name = scrapy.Field()
6    division = scrapy.Field()
7    current_ranking = scrapy.Field()
8    ufc_record = scrapy.Field()

Обход сайта начнётся с функции parse, буду в ней перебирать все ссылки на различные дивизионы, fightmatrix/spiders/fightmatrix_spider.py:

 1import scrapy
 2from fightmatrix.items import FightmatrixItem
 3
 4
 5class FightmatrixSpider(scrapy.Spider):
 6    name = 'fightmatrix_spider'
 7    allowed_domains = ['fightmatrix.com']
 8    start_urls = ['https://www.fightmatrix.com/mma-ranks/']
 9
10    def parse(self, response):
11        for division_link in response.xpath('//td/a/@href').extract():
12            if (
13                'pound' not in division_link.lower() and 
14                'division' not in division_link.lower()
15            ):  
16                div_name = division_link.split('/')[-2]
17                yield response.follow(
18                    '{0}?PageNum=1'.format(division_link),
19                    callback=self.parse_division,
20                    meta={
21                        'page_num': 1,
22                        'div_name': div_name,
23                    },
24                )

Здесь я получаю ссылки на все дивизионы бойцов и передаю некоторые параметры для функции parse_division, которая будет парсить все доступные дивизионы, fightmatrix/spiders/fightmatrix_spider.py:

 1def parse_division(self, response):
 2    page_num = response.meta.get('page_num')
 3    div_name = response.meta.get('div_name')
 4    fighters_on_page = False
 5    for fighter_link in response.xpath(
 6        '//td/a[@class="sherLink"]/@href',
 7    ).extract():
 8        fighters_on_page = True
 9        yield response.follow(
10            fighter_link,
11            callback=self.parse_fighter,
12            meta={
13                'div_name': div_name,
14            },
15        )
16    # go to next page if are some fighters
17    if fighters_on_page:
18        div_url = response.url
19        div_url = div_url[:div_url.index('?PageNum')]
20        page_num += 1
21        yield response.follow(
22            '{0}?PageNum={1}'.format(div_url, page_num),
23            callback=self.parse_division,
24            meta={
25                'page_num': page_num,
26                'div_name': div_name,
27            },
28        )

Здесь я нахожу всех бойцов, вызываю функцию parse_fighter, она будет парсить страничку конкретного бойца, также я перебираю дальнейшие страницы дивизионов, задавая номер странички с помощью переменной page_num. Теперь осталось написать собственно функцию, которая парсит данные по бойцам, fightmatrix/spiders/fightmatrix_spider.py:

 1def parse_fighter(self, response):
 2    f_m_item = FightmatrixItem()
 3    name = response.xpath(
 4        '//div[@class="posttitle"]/h1/a/text()',
 5    ).extract_first()
 6    div_name = response.meta.get('div_name')
 7
 8
 9    current_ranking = ''
10    for ind, ranking in enumerate(response.xpath(
11        '//td[@class="tdRank"]/div[@class="leftCol"]/a/text()',
12    ).extract()):
13        if ind == 0:
14            current_ranking += ranking
15        else:
16            current_ranking += ', ' + ranking
17
18    for ranking in response.xpath(
19        '//td[@class="tdRank"]/div[@class="rightCol"]/a/text()',
20    ).extract():
21        current_ranking += ', ' + ranking
22
23    some_data = response.xpath(
24        '//tr/td[@class="tdRankAlt"]/div[@class="leftCol"]/strong/text()',
25    ).extract()
26    ufc_record = ''
27    for s_d in some_data:
28        if s_d.count('-') == 2:
29            ufc_record = s_d
30            break
31
32
33    f_m_item['division'] = div_name
34    f_m_item['name'] = name
35    f_m_item['current_ranking'] = current_ranking
36    f_m_item['ufc_record'] = ufc_record
37    yield f_m_item

Запустить паука можно например такой командой:

scrapy crawl fightmatrix_spider -o output.csv -t csv, данные будут сохранены как csv в корне проекта. Паук будет работать минут 5, находится порядка 4к бойцов во всех дивизионах.

Вот ссылка на гитхаб проекта.

Метки

scrapy python
Если вам понравился пост, можете поделиться им в соцсетях: