mirror of
https://github.com/Viren070/MediaFusion.git
synced 2025-12-01 23:21:11 +01:00
160 lines
6.4 KiB
Python
160 lines
6.4 KiB
Python
import random
|
|
from urllib.parse import urlparse
|
|
|
|
import scrapy
|
|
|
|
from utils.config import config_manager
|
|
from db.redis_database import REDIS_SYNC_CLIENT
|
|
from utils.const import CATALOG_DATA
|
|
from utils.runtime_const import SPORTS_ARTIFACTS
|
|
|
|
|
|
class SportVideoSpider(scrapy.Spider):
|
|
name = "sport_video"
|
|
categories = config_manager.get_scraper_config(name, "categories")
|
|
|
|
custom_settings = {
|
|
"ITEM_PIPELINES": {
|
|
"mediafusion_scrapy.pipelines.TorrentDownloadAndParsePipeline": 100,
|
|
"mediafusion_scrapy.pipelines.SportVideoParserPipeline": 200,
|
|
"mediafusion_scrapy.pipelines.MovieStorePipeline": 300,
|
|
"mediafusion_scrapy.pipelines.RedisCacheURLPipeline": 400,
|
|
},
|
|
}
|
|
|
|
def __init__(self, scrape_all: str = "false", *args, **kwargs):
|
|
super(SportVideoSpider, self).__init__(*args, **kwargs)
|
|
self.scrape_all = scrape_all.lower() == "true"
|
|
self.redis = REDIS_SYNC_CLIENT
|
|
self.scraped_urls_key = "sport_video_scraped_urls"
|
|
|
|
def __del__(self):
|
|
self.redis.close()
|
|
|
|
def start_requests(self):
|
|
for category, url in self.categories.items():
|
|
yield scrapy.Request(url, self.parse, meta={"category": category})
|
|
|
|
def parse(self, response, **kwargs):
|
|
category = response.meta["category"]
|
|
# Parse the current page URL to extract the base path for comparison
|
|
current_category_base = urlparse(response.url).path.rsplit(".", 1)[0]
|
|
|
|
if self.scrape_all:
|
|
# Navigate through the pagination
|
|
page_links = set(
|
|
response.css("div[id^='wb_Pagination'] ul li a::attr(href)").getall()
|
|
)
|
|
for link in page_links:
|
|
# Ensure the link is not just a 'Next' or 'Prev' button
|
|
if current_category_base in link:
|
|
yield response.follow(
|
|
link, self.parse_page, meta={"category": category}
|
|
)
|
|
# Only scrape the first page
|
|
yield from self.parse_page(response)
|
|
|
|
def parse_page(self, response):
|
|
category = response.meta["category"]
|
|
catalog_mapped = CATALOG_DATA.get(category)
|
|
generic_posters = SPORTS_ARTIFACTS[catalog_mapped]["poster"]
|
|
generic_backgrounds = SPORTS_ARTIFACTS[catalog_mapped]["background"]
|
|
# Generalized selector for all content blocks
|
|
content_blocks = response.css('div[id^="wb_LayoutGrid"]')
|
|
for content in content_blocks:
|
|
# Extract only the first part of the title
|
|
title_words = content.css('div[id^="wb_Text"] strong::text').getall()
|
|
title = "".join(title_words).replace("(NEW)", "").strip()
|
|
|
|
# Extract poster URL
|
|
poster_path = content.css('div[id^="wb_PhotoGallery"] img::attr(src)').get()
|
|
if poster_path:
|
|
poster = response.urljoin(poster_path)
|
|
background = poster
|
|
else:
|
|
poster = random.choice(generic_posters)
|
|
background = random.choice(generic_backgrounds)
|
|
|
|
torrent_data = {
|
|
"title": title.strip(),
|
|
"poster": poster,
|
|
"background": background,
|
|
"parsed_data": {"title": title.strip()},
|
|
"source": "sport-video.org.ua",
|
|
"is_add_title_to_poster": True,
|
|
"catalog": category,
|
|
"type": "movie",
|
|
"scraped_url_key": self.scraped_urls_key,
|
|
}
|
|
|
|
# Extract torrent page link
|
|
torrent_page_link = content.css('div[id^="wb_Shape"] a::attr(href)').get()
|
|
torrent_link = content.css('a[href$=".torrent"]::attr(href)').get()
|
|
if title and torrent_page_link:
|
|
torrent_page_link = response.urljoin(torrent_page_link)
|
|
# Check if URL has been scraped before
|
|
if self.redis.sismember(self.scraped_urls_key, torrent_page_link):
|
|
self.logger.info(
|
|
f"Skipping already scraped URL: {torrent_page_link}"
|
|
)
|
|
continue
|
|
|
|
torrent_data["webpage_url"] = torrent_page_link
|
|
yield response.follow(
|
|
torrent_page_link,
|
|
self.parse_torrent_page,
|
|
meta={"item": torrent_data},
|
|
)
|
|
elif title and torrent_link:
|
|
# Check if URL has been scraped before
|
|
if self.redis.sismember(self.scraped_urls_key, torrent_link):
|
|
self.logger.info(f"Skipping already scraped URL: {torrent_link}")
|
|
continue
|
|
|
|
torrent_data["torrent_link"] = response.urljoin(torrent_link)
|
|
yield torrent_data
|
|
|
|
def parse_torrent_page(self, response):
|
|
# Retrieve passed item data
|
|
base_item = response.meta["item"]
|
|
|
|
# Initialize variables to hold metadata and the current metadata block
|
|
metadata_blocks = []
|
|
current_block = {}
|
|
|
|
table_rows = response.css("table tr")
|
|
for row in table_rows:
|
|
header = (
|
|
row.css("td.cell0 strong::text")
|
|
.extract_first(default="")
|
|
.strip()
|
|
.lower()
|
|
.replace(" ", "_")
|
|
)
|
|
value = " ".join(row.css("td.cell0:nth-child(2) *::text").extract()).strip()
|
|
|
|
# When encountering a 'description', it means a new torrent metadata block starts
|
|
if header == "description" and current_block:
|
|
# Save the current block and start a new one
|
|
metadata_blocks.append(current_block)
|
|
current_block = {}
|
|
|
|
# Add the metadata to the current block
|
|
current_block[header] = value
|
|
|
|
# add the last block
|
|
if current_block:
|
|
metadata_blocks.append(current_block)
|
|
|
|
# Extract all torrent links
|
|
torrent_links = response.css('a[href$=".torrent"]::attr(href)').getall()
|
|
|
|
# Correctly match metadata blocks to torrent links
|
|
for i, link in enumerate(torrent_links):
|
|
item = base_item.copy() # Create a new item for each torrent link
|
|
# If there's corresponding metadata, add it to the item
|
|
if i < len(metadata_blocks):
|
|
item.update(metadata_blocks[i])
|
|
item["torrent_link"] = response.urljoin(link)
|
|
yield item
|