Skip to content

search

gurume.search

SearchMeta dataclass

SearchMeta(
    total_count: int | None,
    current_page: int,
    results_per_page: int,
    total_pages: int | None,
    has_next_page: bool,
    has_prev_page: bool,
    search_time: datetime = _now(),
    source_url: str | None = None,
    source_params: dict[str, str] = dict(),
    cuisine_filter_confidence: CuisineFilterConfidence
    | None = None,
    cuisine_filter_reason: str | None = None,
    area_filter_applied: bool | None = None,
    area_filter_confidence: AreaFilterConfidence
    | None = None,
    area_filter_reason: str | None = None,
)

Search metadata.

SearchPageResult dataclass

SearchPageResult(
    html: str,
    restaurants: list[Restaurant],
    source_url: str,
    source_params: dict[str, str],
)

Fetched search page content and source evidence.

SearchRequest dataclass

SearchRequest(
    area: str | None = None,
    keyword: str | None = None,
    genre_code: str | None = None,
    reservation_date: str | None = None,
    reservation_time: str | None = None,
    party_size: int | None = None,
    sort_type: SortType = SortType.STANDARD,
    page: int = 1,
    max_pages: int = 1,
    include_meta: bool = True,
    timeout: float = 30.0,
)

Generic search request that extends RestaurantSearchRequest.

do async

do() -> SearchResponse

Run the search asynchronously. Deprecated; use search().

Source code in src/gurume/search.py
594
595
596
async def do(self) -> SearchResponse:
    """Run the search asynchronously. Deprecated; use search()."""
    return await self.search()

do_sync

do_sync() -> SearchResponse

Run the search synchronously. Deprecated; use search_sync().

Source code in src/gurume/search.py
590
591
592
def do_sync(self) -> SearchResponse:
    """Run the search synchronously. Deprecated; use search_sync()."""
    return self.search_sync()

search async

search() -> SearchResponse

Run the search asynchronously.

Source code in src/gurume/search.py
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
async def search(self) -> SearchResponse:
    """Run the search asynchronously."""
    try:
        all_restaurants: list[Restaurant] = []
        meta = None

        async with requests.AsyncSession(
            timeout=self.timeout,
            allow_redirects=True,
            impersonate=DEFAULT_IMPERSONATE,
        ) as client:
            start_page = self.page
            end_page = self.page + self.max_pages

            for page in range(start_page, end_page):
                request = self._create_restaurant_request(page)
                page_result = await self._search_page_async(client, request)
                all_restaurants.extend(page_result.restaurants)
                meta = self._update_meta(meta, page_result, page)
                if meta and meta.total_count == 0:
                    break

                # Stop when the current page has no results.
                if not page_result.restaurants:
                    break

        status = SearchStatus.SUCCESS if all_restaurants else SearchStatus.NO_RESULTS
        warnings = [
            *self._annotate_area_filter(meta, all_restaurants),
            *self._annotate_cuisine_filter(meta, all_restaurants),
        ]
    except SEARCH_EXCEPTIONS as e:
        return SearchResponse(
            status=SearchStatus.ERROR,
            error_message=str(e),
        )
    else:
        return SearchResponse(
            status=status,
            restaurants=all_restaurants,
            meta=meta,
            warnings=warnings,
        )

search_sync

search_sync() -> SearchResponse

Run the search synchronously.

Source code in src/gurume/search.py
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
def search_sync(self) -> SearchResponse:
    """Run the search synchronously."""
    try:
        all_restaurants: list[Restaurant] = []
        meta = None

        start_page = self.page
        end_page = self.page + self.max_pages

        for page in range(start_page, end_page):
            request = self._create_restaurant_request(page)
            page_result = self._search_page_sync(request)
            all_restaurants.extend(page_result.restaurants)
            meta = self._update_meta(meta, page_result, page)
            if meta and meta.total_count == 0:
                break

            # Stop when the current page has no results.
            if not page_result.restaurants:
                break

        status = SearchStatus.SUCCESS if all_restaurants else SearchStatus.NO_RESULTS
        warnings = [
            *self._annotate_area_filter(meta, all_restaurants),
            *self._annotate_cuisine_filter(meta, all_restaurants),
        ]
    except SEARCH_EXCEPTIONS as e:
        return SearchResponse(
            status=SearchStatus.ERROR,
            error_message=str(e),
        )
    else:
        return SearchResponse(
            status=status,
            restaurants=all_restaurants,
            meta=meta,
            warnings=warnings,
        )

SearchResponse dataclass

SearchResponse(
    status: SearchStatus,
    restaurants: list[Restaurant] = list(),
    meta: SearchMeta | None = None,
    error_message: str | None = None,
    warnings: list[str] = list(),
)

Search response.

filter

filter(
    condition: Callable[[Restaurant], bool] | None = None,
    min_rating: float | None = None,
    min_review_count: int | None = None,
) -> SearchResponse

Filter restaurants.

Parameters:

Name Type Description Default
condition Callable[[Restaurant], bool] | None

Custom filter predicate.

None
min_rating float | None

Minimum rating.

None
min_review_count int | None

Minimum review count.

None

Returns:

Type Description
SearchResponse

New SearchResponse containing the filtered restaurants.

Source code in src/gurume/search.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
def filter(
    self,
    condition: Callable[[Restaurant], bool] | None = None,
    min_rating: float | None = None,
    min_review_count: int | None = None,
) -> SearchResponse:
    """Filter restaurants.

    Args:
        condition: Custom filter predicate.
        min_rating: Minimum rating.
        min_review_count: Minimum review count.

    Returns:
        New SearchResponse containing the filtered restaurants.
    """
    filtered = self.restaurants

    if min_rating is not None:
        filtered = [r for r in filtered if r.rating and r.rating >= min_rating]

    if min_review_count is not None:
        filtered = [r for r in filtered if r.review_count and r.review_count >= min_review_count]

    if condition is not None:
        filtered = [r for r in filtered if condition(r)]

    return SearchResponse(
        status=self.status,
        restaurants=filtered,
        meta=self.meta,
        error_message=self.error_message,
        warnings=list(self.warnings),
    )

sort_by

sort_by(key: str, reverse: bool = False) -> SearchResponse

Sort by the specified field.

Parameters:

Name Type Description Default
key str

Sort field: rating, review_count, save_count, or name.

required
reverse bool

Whether to sort in reverse order. Defaults to False.

False

Returns:

Type Description
SearchResponse

New SearchResponse containing the sorted restaurants.

Source code in src/gurume/search.py
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
def sort_by(self, key: str, reverse: bool = False) -> SearchResponse:
    """Sort by the specified field.

    Args:
        key: Sort field: rating, review_count, save_count, or name.
        reverse: Whether to sort in reverse order. Defaults to False.

    Returns:
        New SearchResponse containing the sorted restaurants.
    """
    sorted_restaurants = sorted(
        self.restaurants,
        key=lambda r: getattr(r, key, 0) or 0,
        reverse=reverse,
    )

    return SearchResponse(
        status=self.status,
        restaurants=sorted_restaurants,
        meta=self.meta,
        error_message=self.error_message,
        warnings=list(self.warnings),
    )

to_dict

to_dict() -> dict

Convert to a dictionary.

Returns:

Type Description
dict

Dictionary containing all response data.

Source code in src/gurume/search.py
187
188
189
190
191
192
193
194
195
196
197
198
199
def to_dict(self) -> dict:
    """Convert to a dictionary.

    Returns:
        Dictionary containing all response data.
    """
    return {
        "status": self.status.value,
        "restaurants": [asdict(r) for r in self.restaurants],
        "meta": asdict(self.meta) if self.meta else None,
        "error_message": self.error_message,
        "warnings": list(self.warnings),
    }

to_json

to_json(indent: int = 2) -> str

Export as a JSON string.

Parameters:

Name Type Description Default
indent int

Number of spaces for JSON indentation.

2

Returns:

Type Description
str

JSON string.

Source code in src/gurume/search.py
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
def to_json(self, indent: int = 2) -> str:
    """Export as a JSON string.

    Args:
        indent: Number of spaces for JSON indentation.

    Returns:
        JSON string.
    """
    data = {
        "status": self.status.value,
        "restaurants": [asdict(r) for r in self.restaurants],
        "meta": asdict(self.meta) if self.meta else None,
        "error_message": self.error_message,
        "warnings": self.warnings,
    }
    return json.dumps(data, ensure_ascii=False, indent=indent, default=str)

top

top(n: int) -> SearchResponse

Take the first N restaurants.

Parameters:

Name Type Description Default
n int

Number of restaurants to take.

required

Returns:

Type Description
SearchResponse

New SearchResponse containing the first N restaurants.

Source code in src/gurume/search.py
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
def top(self, n: int) -> SearchResponse:
    """Take the first N restaurants.

    Args:
        n: Number of restaurants to take.

    Returns:
        New SearchResponse containing the first N restaurants.
    """
    return SearchResponse(
        status=self.status,
        restaurants=self.restaurants[:n],
        meta=self.meta,
        error_message=self.error_message,
        warnings=list(self.warnings),
    )

SearchStatus

Bases: StrEnum

Search status.