mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-22 23:31:12 +02:00
chore: bumped version to 0.0.31
This commit is contained in:
parent
8df8565e0a
commit
1c9ab207ef
56 changed files with 520 additions and 190 deletions
|
|
@ -31,6 +31,7 @@ if we add another sticky vendor is to extend ``_STICKY_HOSTS``.
|
|||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import contextlib
|
||||
import logging
|
||||
import random
|
||||
import sys
|
||||
|
|
@ -158,8 +159,7 @@ async def _vet_fresh_ip(url: str, base: str) -> str | None:
|
|||
return proxy if await _precheck(url, proxy) else None
|
||||
|
||||
tasks = [
|
||||
asyncio.create_task(vet(_sticky_variant(base)))
|
||||
for _ in range(_VET_CONCURRENCY)
|
||||
asyncio.create_task(vet(_sticky_variant(base))) for _ in range(_VET_CONCURRENCY)
|
||||
]
|
||||
winner: str | None = None
|
||||
for fut in asyncio.as_completed(tasks):
|
||||
|
|
@ -306,10 +306,8 @@ async def _drop_session_on_loop(mobile: bool) -> None:
|
|||
async with _session_lock:
|
||||
session = _sessions.pop(mobile, None)
|
||||
if session is not None:
|
||||
try:
|
||||
with contextlib.suppress(Exception): # already dead; nothing to salvage
|
||||
await session.close()
|
||||
except Exception: # already dead; nothing to salvage
|
||||
pass
|
||||
|
||||
|
||||
async def _drop_session(mobile: bool) -> None:
|
||||
|
|
|
|||
|
|
@ -218,7 +218,9 @@ def parse_organic(doc: Adaptor, *, include_icons: bool = False) -> list[OrganicR
|
|||
return results
|
||||
|
||||
|
||||
def parse_paid_results(doc: Adaptor, *, include_icons: bool = False) -> list[PaidResult]:
|
||||
def parse_paid_results(
|
||||
doc: Adaptor, *, include_icons: bool = False
|
||||
) -> list[PaidResult]:
|
||||
"""Text ads (``div[data-text-ad]``), covering the top and bottom ad blocks.
|
||||
|
||||
Fields mirror an organic result: the heading is the title, the ad's anchor
|
||||
|
|
@ -239,7 +241,11 @@ def parse_paid_results(doc: Adaptor, *, include_icons: bool = False) -> list[Pai
|
|||
description = None
|
||||
for cand in block.css(".Va3FIb"):
|
||||
text = _text(cand)
|
||||
if text and text != title and (description is None or len(text) > len(description)):
|
||||
if (
|
||||
text
|
||||
and text != title
|
||||
and (description is None or len(text) > len(description))
|
||||
):
|
||||
description = text
|
||||
slot = block.attrib.get("data-ta-slot-pos")
|
||||
ads.append(
|
||||
|
|
|
|||
|
|
@ -291,8 +291,8 @@ async def _user_flow(
|
|||
date_limit=input_model.postDateLimit,
|
||||
):
|
||||
# A user listing mixes posts (t3) and comments (t1); a post has a title.
|
||||
parsed = parse_post(data) if data.get("title") is not None else parse_comment(
|
||||
data
|
||||
parsed = (
|
||||
parse_post(data) if data.get("title") is not None else parse_comment(data)
|
||||
)
|
||||
item = _emit(parsed, include_nsfw=input_model.includeNSFW)
|
||||
if item is not None:
|
||||
|
|
@ -401,8 +401,7 @@ async def iter_reddit(
|
|||
continue
|
||||
resolved.append(r)
|
||||
jobs = [
|
||||
_dispatch(r, input_model)
|
||||
for r in _capped_targets(resolved, input_model)
|
||||
_dispatch(r, input_model) for r in _capped_targets(resolved, input_model)
|
||||
]
|
||||
async for item in fan_out(jobs):
|
||||
yield item
|
||||
|
|
@ -449,9 +448,7 @@ async def scrape_reddit(
|
|||
results: list[dict[str, Any]] = []
|
||||
async for item in iter_reddit(input_model):
|
||||
results.append(item)
|
||||
emit_progress(
|
||||
"scraping", current=len(results), total=limit, unit="item"
|
||||
)
|
||||
emit_progress("scraping", current=len(results), total=limit, unit="item")
|
||||
if limit is not None and len(results) >= limit:
|
||||
break
|
||||
return results
|
||||
|
|
|
|||
|
|
@ -28,9 +28,7 @@ _REDDIT_HOSTS = frozenset(
|
|||
)
|
||||
|
||||
# Listing sorts that can appear as a trailing subreddit path segment.
|
||||
_SUBREDDIT_SORTS = frozenset(
|
||||
{"hot", "new", "top", "rising", "controversial", "best"}
|
||||
)
|
||||
_SUBREDDIT_SORTS = frozenset({"hot", "new", "top", "rising", "controversial", "best"})
|
||||
_USER_CONTENT = frozenset({"overview", "submitted", "comments"})
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -69,9 +69,7 @@ def _fetch_subtitles_sync(
|
|||
api = _build_client()
|
||||
try:
|
||||
transcript_list = api.list(video_id)
|
||||
transcript = _select_transcript(
|
||||
transcript_list, language, prefer_generated
|
||||
)
|
||||
transcript = _select_transcript(transcript_list, language, prefer_generated)
|
||||
fetched = transcript.fetch()
|
||||
break
|
||||
except RequestBlocked: # covers IpBlocked; rotate to a fresh exit IP
|
||||
|
|
|
|||
|
|
@ -91,7 +91,9 @@ _CURRENCY_AMOUNT_RE = re.compile(
|
|||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
_STRIP_XPATH = "//script | //style | //noscript | //template | //svg | //iframe | //head"
|
||||
_STRIP_XPATH = (
|
||||
"//script | //style | //noscript | //template | //svg | //iframe | //head"
|
||||
)
|
||||
|
||||
|
||||
def _visible_text(raw_html: str) -> str:
|
||||
|
|
@ -278,9 +280,7 @@ class WebCrawlerConnector:
|
|||
else:
|
||||
reached_without_content = True
|
||||
errors.append("Scrapling static: empty extraction")
|
||||
self._log_tier_outcome(
|
||||
"scrapling-static", url, tier_start, "empty"
|
||||
)
|
||||
self._log_tier_outcome("scrapling-static", url, tier_start, "empty")
|
||||
except Exception as exc:
|
||||
errors.append(f"Scrapling static: {exc!s}")
|
||||
self._log_tier_outcome(
|
||||
|
|
|
|||
|
|
@ -156,9 +156,7 @@ class _SiteSpider(Spider):
|
|||
# ladder + proxy rotation; never let the spider re-fetch on top of that.
|
||||
return False
|
||||
|
||||
async def parse(
|
||||
self, response: Response
|
||||
) -> AsyncGenerator[Request | None, None]:
|
||||
async def parse(self, response: Response) -> AsyncGenerator[Request | None, None]:
|
||||
outcome: CrawlOutcome = response._outcome # type: ignore[attr-defined]
|
||||
depth: int = response.meta.get("_depth", 0)
|
||||
referrer: str | None = response.meta.get("_referrer")
|
||||
|
|
|
|||
|
|
@ -73,9 +73,7 @@ def _anchor_context(anchor: Any) -> str:
|
|||
return ""
|
||||
|
||||
|
||||
def extract_link_records(
|
||||
page_html: str | None, base_url: str
|
||||
) -> list[dict[str, str]]:
|
||||
def extract_link_records(page_html: str | None, base_url: str) -> list[dict[str, str]]:
|
||||
"""Structured ``<a>`` inventory: ``{url, text, context, rel, kind}`` per target.
|
||||
|
||||
``kind`` is one of ``internal`` (same site as ``base_url``), ``external``,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue