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
591
592
593
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
587
588
589
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
542
543
544
545
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
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),
            http_status=http_status_code(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
502
503
504
505
506
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
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),
            http_status=http_status_code(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(),
    http_status: int | None = None,
)

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
 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
127
128
129
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),
        http_status=self.http_status,
    )

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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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),
        http_status=self.http_status,
    )

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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
def to_dict(self) -> dict:
    """Convert to a dictionary.

    Returns:
        Dictionary containing all response data.
    """
    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": list(self.warnings),
    }
    if self.http_status is not None:
        data["http_status"] = self.http_status
    return data

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
174
175
176
177
178
179
180
181
182
183
def to_json(self, indent: int = 2) -> str:
    """Export as a JSON string.

    Args:
        indent: Number of spaces for JSON indentation.

    Returns:
        JSON string.
    """
    return json.dumps(self.to_dict(), 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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
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),
        http_status=self.http_status,
    )

SearchStatus

Bases: StrEnum

Search status.