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

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

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

10 мая 2022 г.

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

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

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

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

 1 import scrapy
 2 from fightmatrix.items import FightmatrixItem
 3 
 4 
 5 class 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 создается наш конечный класс, используя который мы будем парсить сайт. Сразу пропишу некоторые поля:

1 import scrapy
2 
3 
4 class 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:

 1 import scrapy
 2 from fightmatrix.items import FightmatrixItem
 3 
 4 
 5 class 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:

 1 def 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:

 1 def 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
Если вам понравился пост, можете поделиться им в соцсетях: