scraper2-hj3415 2.1.2__py3-none-any.whl → 2.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
scraper2/.DS_Store CHANGED
Binary file
@@ -10,7 +10,6 @@ class PlaywrightBrowser:
10
10
  self.page = page
11
11
 
12
12
  async def goto(self, url: str, timeout_ms: int = 10_000) -> None:
13
- self.page.set_default_timeout(10_000)
14
13
  await self.page.goto(url, timeout=timeout_ms)
15
14
 
16
15
  async def title(self) -> str:
@@ -1,7 +1,8 @@
1
1
  #scraper2/adapters/out/sinks/memory/c101_memory_sink.py
2
2
  from __future__ import annotations
3
3
 
4
- from typing import Iterable
4
+ from datetime import datetime
5
+ from typing import Iterable, Optional
5
6
 
6
7
  from contracts.nfs.c101 import C101DTO
7
8
  from scraper2.adapters.out.sinks.memory.store import InMemoryStore
@@ -13,8 +14,13 @@ class MemoryC101Sink(C101SinkPort):
13
14
  def __init__(self, store: InMemoryStore[C101DTO]):
14
15
  self._store = store
15
16
 
16
- async def write(self, dto: C101DTO) -> None:
17
+ async def write(self, dto: C101DTO, *, asof: Optional[datetime] = None) -> None:
17
18
  await self._store.put(_ENDPOINT, dto.코드, dto)
18
19
 
19
- async def write_many(self, dtos: Iterable[C101DTO]) -> None:
20
+ async def write_many(
21
+ self,
22
+ dtos: Iterable[C101DTO],
23
+ *,
24
+ asof: Optional[datetime] = None,
25
+ ) -> None:
20
26
  await self._store.put_many(_ENDPOINT, ((d.코드, d) for d in dtos))
@@ -1,7 +1,8 @@
1
1
  # scraper2/adapters/out/sinks/memory/c103_memory_sink.py
2
2
  from __future__ import annotations
3
3
 
4
- from typing import Iterable
4
+ from datetime import datetime
5
+ from typing import Iterable, Optional
5
6
 
6
7
  from contracts.nfs.c103 import C103DTO
7
8
  from scraper2.adapters.out.sinks.memory.store import InMemoryStore
@@ -13,8 +14,13 @@ class MemoryC103Sink(C103SinkPort):
13
14
  def __init__(self, store: InMemoryStore[C103DTO]):
14
15
  self._store = store
15
16
 
16
- async def write(self, dto: C103DTO) -> None:
17
+ async def write(self, dto: C103DTO, *, asof: Optional[datetime] = None) -> None:
17
18
  await self._store.put(_ENDPOINT, dto.코드, dto)
18
19
 
19
- async def write_many(self, dtos: Iterable[C103DTO]) -> None:
20
+ async def write_many(
21
+ self,
22
+ dtos: Iterable[C103DTO],
23
+ *,
24
+ asof: Optional[datetime] = None,
25
+ ) -> None:
20
26
  await self._store.put_many(_ENDPOINT, ((d.코드, d) for d in dtos))
@@ -1,7 +1,8 @@
1
1
  # scraper2/adapters/out/sinks/memory/c104_memory_sink.py
2
2
  from __future__ import annotations
3
3
 
4
- from typing import Iterable
4
+ from datetime import datetime
5
+ from typing import Iterable, Optional
5
6
 
6
7
  from contracts.nfs.c104 import C104DTO
7
8
  from scraper2.adapters.out.sinks.memory.store import InMemoryStore
@@ -13,8 +14,13 @@ class MemoryC104Sink(C104SinkPort):
13
14
  def __init__(self, store: InMemoryStore[C104DTO]):
14
15
  self._store = store
15
16
 
16
- async def write(self, dto: C104DTO) -> None:
17
+ async def write(self, dto: C104DTO, *, asof: Optional[datetime] = None) -> None:
17
18
  await self._store.put(_ENDPOINT, dto.코드, dto)
18
19
 
19
- async def write_many(self, dtos: Iterable[C104DTO]) -> None:
20
+ async def write_many(
21
+ self,
22
+ dtos: Iterable[C104DTO],
23
+ *,
24
+ asof: Optional[datetime] = None,
25
+ ) -> None:
20
26
  await self._store.put_many(_ENDPOINT, ((d.코드, d) for d in dtos))
@@ -1,7 +1,8 @@
1
1
  #scraper2/adapters/out/sinks/memory/c106_memory_sink.py
2
2
  from __future__ import annotations
3
3
 
4
- from typing import Iterable
4
+ from datetime import datetime
5
+ from typing import Iterable, Optional
5
6
 
6
7
  from contracts.nfs.c106 import C106DTO
7
8
  from scraper2.adapters.out.sinks.memory.store import InMemoryStore
@@ -13,8 +14,13 @@ class MemoryC106Sink(C106SinkPort):
13
14
  def __init__(self, store: InMemoryStore[C106DTO]):
14
15
  self._store = store
15
16
 
16
- async def write(self, dto: C106DTO) -> None:
17
+ async def write(self, dto: C106DTO, *, asof: Optional[datetime] = None) -> None:
17
18
  await self._store.put(_ENDPOINT, dto.코드, dto)
18
19
 
19
- async def write_many(self, dtos: Iterable[C106DTO]) -> None:
20
+ async def write_many(
21
+ self,
22
+ dtos: Iterable[C106DTO],
23
+ *,
24
+ asof: Optional[datetime] = None,
25
+ ) -> None:
20
26
  await self._store.put_many(_ENDPOINT, ((d.코드, d) for d in dtos))
@@ -1,7 +1,8 @@
1
1
  #scraper2/adapters/out/sinks/memory/c108_memory_sink.py
2
2
  from __future__ import annotations
3
3
 
4
- from typing import Iterable
4
+ from datetime import datetime
5
+ from typing import Iterable, Optional
5
6
 
6
7
  from contracts.nfs.c108 import C108DTO
7
8
  from scraper2.adapters.out.sinks.memory.store import InMemoryStore
@@ -13,8 +14,13 @@ class MemoryC108Sink(C108SinkPort):
13
14
  def __init__(self, store: InMemoryStore[C108DTO]):
14
15
  self._store = store
15
16
 
16
- async def write(self, dto: C108DTO) -> None:
17
+ async def write(self, dto: C108DTO, *, asof: Optional[datetime] = None) -> None:
17
18
  await self._store.put(_ENDPOINT, dto.코드, dto)
18
19
 
19
- async def write_many(self, dtos: Iterable[C108DTO]) -> None:
20
+ async def write_many(
21
+ self,
22
+ dtos: Iterable[C108DTO],
23
+ *,
24
+ asof: Optional[datetime] = None,
25
+ ) -> None:
20
26
  await self._store.put_many(_ENDPOINT, ((d.코드, d) for d in dtos))
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
 
4
4
  import os
5
5
  from dataclasses import dataclass
6
- from typing import Literal
6
+ from typing import Literal, Optional
7
7
 
8
8
  from pymongo.asynchronous.database import AsyncDatabase
9
9
 
@@ -109,6 +109,23 @@ class Usecases:
109
109
  store: InMemoryStore | None = None # ✅ memory일 때만
110
110
  mongo: Mongo | None = None # ✅ mongo일 때만
111
111
  db: AsyncDatabase | None = None # ✅ mongo일 때만
112
+ browser_factory: Optional[BrowserFactoryPort] = None
113
+
114
+ async def aclose(self) -> None:
115
+ # 1) playwright 먼저 닫기 (subprocess 정리)
116
+ if self.browser_factory is not None:
117
+ close = getattr(self.browser_factory, "aclose", None)
118
+ if callable(close):
119
+ await close()
120
+
121
+ # 2) mongo 닫기
122
+ if self.mongo is not None:
123
+ close = getattr(self.mongo, "close", None)
124
+ if callable(close):
125
+ out = close()
126
+ if hasattr(out, "__await__"):
127
+ await out
128
+
112
129
 
113
130
 
114
131
  # -------------------------
@@ -1,13 +1,14 @@
1
1
  # scraper2/app/ports/ingest_port.py
2
- from typing import Protocol, Iterable
2
+ from typing import Protocol, Iterable, Optional, Sequence, Any
3
3
  from datetime import datetime
4
4
 
5
5
  class IngestPort(Protocol):
6
6
  async def execute_many(
7
7
  self,
8
- codes: list[str],
8
+ codes: Iterable[str],
9
9
  *,
10
10
  sleep_sec: float = ...,
11
- asof: datetime | None = None,
12
- ) -> list[object]:
13
- ...
11
+ asof: Optional[datetime] = None,
12
+ ) -> Sequence[Any]:
13
+ ...
14
+
scraper2/main.py CHANGED
@@ -233,7 +233,10 @@ def nfs_one(
233
233
  else:
234
234
  typer.echo(_dto_to_pretty(dto))
235
235
  finally:
236
- if getattr(ucs, "mongo", None) is not None:
236
+ close = getattr(ucs, "aclose", None)
237
+ if callable(close):
238
+ await close()
239
+ elif getattr(ucs, "mongo", None) is not None:
237
240
  await _maybe_await_close(ucs.mongo)
238
241
 
239
242
  asyncio.run(_run())
@@ -281,7 +284,10 @@ def nfs_all(
281
284
  progress_every=1, # chunk마다
282
285
  )
283
286
  finally:
284
- if getattr(ucs, "mongo", None) is not None:
287
+ close = getattr(ucs, "aclose", None)
288
+ if callable(close):
289
+ await close()
290
+ elif getattr(ucs, "mongo", None) is not None:
285
291
  await _maybe_await_close(ucs.mongo)
286
292
 
287
293
  asyncio.run(_run())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scraper2-hj3415
3
- Version: 2.1.2
3
+ Version: 2.3.0
4
4
  Summary: Naver WiseReport scraper
5
5
  Keywords: example,demo
6
6
  Author-email: Hyungjin Kim <hj3415@gmail.com>
@@ -1,19 +1,19 @@
1
- scraper2/.DS_Store,sha256=miZHKI70yhXtniLCotYbxAAOTB3ML9T6Tb8xQYPeK8w,6148
1
+ scraper2/.DS_Store,sha256=sEtRhy6uiX4PgYuHnRIsUN_QtI0jR0lSLi4kYurHsso,6148
2
2
  scraper2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- scraper2/main.py,sha256=SG0h5swYbHiIcgwpk7yNq7lcCEkdOMz3XM8u41qNtLo,9224
3
+ scraper2/main.py,sha256=qkdepCUXBooOXgwA0eJCg66wY1HFM2iLjBVONGeEVDk,9450
4
4
  scraper2/adapters/out/.DS_Store,sha256=nUqwRB5F2DM82P8BALYvDI0YoD1UbmngfSi8ukKkY7E,6148
5
5
  scraper2/adapters/out/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  scraper2/adapters/out/playwright/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- scraper2/adapters/out/playwright/browser.py,sha256=XomDThsVhsd5MdwhatgXyaCocs1XCjYEKC_YHmo1jsk,3988
7
+ scraper2/adapters/out/playwright/browser.py,sha256=cjz-1iz3U2fmY0tntO5h4NADfW4hYtusCfPTCqSo2NM,3942
8
8
  scraper2/adapters/out/playwright/browser_factory.py,sha256=y008Dbu6VmzrEe7zn7CbODndQEVJtv_EBu04GsMbPGM,3697
9
9
  scraper2/adapters/out/playwright/session.py,sha256=hQDmYpi7pIVDjkymaTKQzJVWUsRRlvJg1V777V8q44M,3727
10
10
  scraper2/adapters/out/sinks/.DS_Store,sha256=c6VOGBl6bMmFzab335dcT09WinGd4BCZXZiPjrZjd7o,6148
11
11
  scraper2/adapters/out/sinks/memory/__init__.py,sha256=djvn50E0dBZr-H6Xmh9FMYalG2Zc0jL5kTXaBjnRaRo,400
12
- scraper2/adapters/out/sinks/memory/c101_memory_sink.py,sha256=klVgT_ra8EQYjJCk6ilWDkrNG3dj_ITP-eqdwX07nY4,682
13
- scraper2/adapters/out/sinks/memory/c103_memory_sink.py,sha256=hov3yH3uQqFie1BzxHa3GKsHjm_e5011ItZ4AiqaJIg,683
14
- scraper2/adapters/out/sinks/memory/c104_memory_sink.py,sha256=-cmNhK17OdsFfVklJjQFF4IWJvmH5ppGcjnpLf8VOns,683
15
- scraper2/adapters/out/sinks/memory/c106_memory_sink.py,sha256=xyrMDjIpPZJ2CHc8687weEF72wKcVl_flFp7PU6GNdo,682
16
- scraper2/adapters/out/sinks/memory/c108_memory_sink.py,sha256=HYxZ1YymdSlGzPpaNsdQGZhpzVr-ArgNgM0PyJdfubA,682
12
+ scraper2/adapters/out/sinks/memory/c101_memory_sink.py,sha256=yqIYGF43-Jja-IlFo6o6HcuL4RS0CEKRvqS8IULqRC8,833
13
+ scraper2/adapters/out/sinks/memory/c103_memory_sink.py,sha256=WWjkaGp8v0TW-_NydRfv7wRDMrvItkv1qqvlTh_XUbg,850
14
+ scraper2/adapters/out/sinks/memory/c104_memory_sink.py,sha256=Pa-1limYsYtQ0Y3qIU3M0f-QWbagUEIuzfzEtEgBgW4,850
15
+ scraper2/adapters/out/sinks/memory/c106_memory_sink.py,sha256=UNse5lDJla-nTFgsytovw45SRhnGVWH0HWGR8RQRL1Q,849
16
+ scraper2/adapters/out/sinks/memory/c108_memory_sink.py,sha256=XrDy28FtGbLllzTDance9R3LtVYvRP9GHLJVG-npEUI,849
17
17
  scraper2/adapters/out/sinks/memory/store.py,sha256=h4dwiCF5gne5kloRdD78NWlqtcaailIqoId9xAjtBk4,2738
18
18
  scraper2/adapters/out/sinks/mongo/__init__.py,sha256=YmEZqNqh7S4PFTufxd5sCF2k24rTOsxY3ZFrFVyQzh8,382
19
19
  scraper2/adapters/out/sinks/mongo/c101_mongo_sink.py,sha256=CpcafwjBJ-Jo-sm02hRC1H214B4aKfvV5MNoNP1AfxQ,1270
@@ -22,7 +22,7 @@ scraper2/adapters/out/sinks/mongo/c104_mongo_sink.py,sha256=IicVnc2fyeBXoBbgMasB
22
22
  scraper2/adapters/out/sinks/mongo/c106_mongo_sink.py,sha256=FMdCp8WVjPwidnh7tIPUoViQWr48O16xtB34O_iCtJI,1203
23
23
  scraper2/adapters/out/sinks/mongo/c108_mongo_sink.py,sha256=eSvIRtofWvNKVPchglwL1mOw5hsKDpUfNz5EOum-H3Y,1203
24
24
  scraper2/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- scraper2/app/composition.py,sha256=HijMEE-2lMEMiYKlVN9ZWJD-E4vwgzIf9-plYzoSwGc,6229
25
+ scraper2/app/composition.py,sha256=I3kpBntvnwuYWrTxTk-VQDXjIJuoM9vqEIApOLFphns,6820
26
26
  scraper2/app/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  scraper2/app/parsing/_converters.py,sha256=z0kSL4nQnqq5w7QfJZBSbjZOLo1JhoqqDLpqlEAN4bo,1815
28
28
  scraper2/app/parsing/_normalize.py,sha256=2qqbXxTbzbuYlu7ttzQjyKgatFnwopme2b_fd0zahio,3738
@@ -32,7 +32,7 @@ scraper2/app/parsing/c104_parser.py,sha256=NGnzdVbhdqXFqJphwEDSlJPnM18RU759FCgry
32
32
  scraper2/app/parsing/c106_parser.py,sha256=JCml8HHnczgMUVnUkRI8AMEJ9mog1dOJfdd6hQKtv9I,4505
33
33
  scraper2/app/parsing/c108_parser.py,sha256=VEzzXliatoRdxR2_uSnHMHLNvV5h2irYiyoXAMQm8jc,1961
34
34
  scraper2/app/ports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
- scraper2/app/ports/ingest_port.py,sha256=RHaRXJanq4VdDUXr42pEJr0vWru7zlIHNOTv7k940os,316
35
+ scraper2/app/ports/ingest_port.py,sha256=mm8jzoaJeiqm2CCznzD347gEzLu7doBjpEwzbRu0R3A,351
36
36
  scraper2/app/ports/browser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
37
  scraper2/app/ports/browser/browser_factory_port.py,sha256=dJ3JCc38MVF7wPmCH4MO3BdnHIXE5wSmfsV7cLysJ54,401
38
38
  scraper2/app/ports/browser/browser_port.py,sha256=tFYkdCeTCF-5XHvT1duioj31ytsc-ATQpmEgposi1X4,1133
@@ -56,8 +56,8 @@ scraper2/app/usecases/ingest/ingest_c103.py,sha256=T_IKs5ikckin_05FnL-dxirAW1PPa
56
56
  scraper2/app/usecases/ingest/ingest_c104.py,sha256=2rGTcFbsATsn3d2KsSEkL5x4fmkGo7x9MHrysoxiICM,1150
57
57
  scraper2/app/usecases/ingest/ingest_c106.py,sha256=mQrbASbKVUQyVcIWiXzIczbX-1mNR5NGk760enVCfvo,1190
58
58
  scraper2/app/usecases/ingest/ingest_c108.py,sha256=49ULzdl0dN6z3istAKg29PcD5wHTxYholqAZiIEmUzU,1191
59
- scraper2_hj3415-2.1.2.dist-info/entry_points.txt,sha256=jUNx7ZJQedQ3QnsDN1ompQ0PjwdvVmnKdHHFMfQQPlI,46
60
- scraper2_hj3415-2.1.2.dist-info/licenses/LICENSE,sha256=QBiVGQuKAESeCfQE344Ik2ex6g2zfYdu9WqrRWydxIs,1068
61
- scraper2_hj3415-2.1.2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
62
- scraper2_hj3415-2.1.2.dist-info/METADATA,sha256=sSKsVoUEyhyRW5pqaKM7rytCf60aaW8xavVoRj_wxzo,3457
63
- scraper2_hj3415-2.1.2.dist-info/RECORD,,
59
+ scraper2_hj3415-2.3.0.dist-info/entry_points.txt,sha256=jUNx7ZJQedQ3QnsDN1ompQ0PjwdvVmnKdHHFMfQQPlI,46
60
+ scraper2_hj3415-2.3.0.dist-info/licenses/LICENSE,sha256=QBiVGQuKAESeCfQE344Ik2ex6g2zfYdu9WqrRWydxIs,1068
61
+ scraper2_hj3415-2.3.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
62
+ scraper2_hj3415-2.3.0.dist-info/METADATA,sha256=QvB781yiOX_OPA6sCcBfbSCu-lxgS7edswJq0064v4I,3457
63
+ scraper2_hj3415-2.3.0.dist-info/RECORD,,