This repository was archived by the owner on Oct 11, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscraper.py
More file actions
99 lines (86 loc) · 3.18 KB
/
Copy pathscraper.py
File metadata and controls
99 lines (86 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from aio_pika import IncomingMessage
from la_stopwatch import Stopwatch
from page_fetcher import Fetcher
from page_infra import Infra
from page_models import SKU
from page_parser import Parser
from pydantic import AnyHttpUrl
from rabbit_models.page_scraper import Body
from structlog.stdlib import BoundLogger
class Scraper:
def __init__(
self,
redis_url: str,
mongo_url: str,
meilisearch_url: str,
meilisearch_key: str,
logger: BoundLogger,
):
self._logger = logger
self._fetcher = Fetcher(logger=logger)
self._parser = Parser(logger=logger)
self._infra = Infra(
redis_url=redis_url,
mongo_url=mongo_url,
meilisearch_url=meilisearch_url,
meilisearch_key=meilisearch_key,
logger=logger,
)
async def setup(self):
await self._infra.setup_databases()
await self._infra.setup_catalog_database()
async def on_message(self, message: IncomingMessage) -> None:
"""
Scrape URLs and send their SKUs to database.
This function is a little complicated because:
1 - fetcher is a coroutine that can receive
a url at any time and return it content
2 - parser is a generator that can receive
a content at any time and return an item
3 - There is a *while* loop that utilizes
both mechanics so at any time the parser can
pass a URL for the fetcher and get it content
"""
stopwatch = Stopwatch()
body = Body.parse_raw(message.body)
marketplace = body.marketplace
urls = body.urls
skus = []
urls = await self._infra.discard_recent_urls(
urls=urls,
marketplace=marketplace,
)
urls = await self._infra.discard_old_urls(
urls=urls,
marketplace=marketplace,
)
pages = await self._fetcher.fetch(
urls=urls,
marketplace=marketplace,
)
async for text, url in pages:
items = self._parser.parse_sku(text=text, url=url, marketplace=marketplace)
for item in items:
while isinstance(item, AnyHttpUrl):
text, url = await pages.asend(item)
item = items.send((text, url))
if isinstance(item, SKU):
skus.append(item)
else:
self._logger.warning(
event="Item ignored",
item=str(item),
url=url,
marketplace=marketplace,
)
await self._infra.insert_skus(skus=skus, marketplace=marketplace)
await self._infra.update_historics(skus=skus, marketplace=marketplace)
await self._infra.insert_snapshots(skus=skus, marketplace=marketplace)
await self._infra.update_relatives(skus=skus, marketplace=marketplace)
await message.ack()
self._logger.info(
event="Message processed",
urls=urls,
marketplace=marketplace,
duration=str(stopwatch),
)