Google Hotels Search Scraper
Pricing
$2.39 / 1,000 hotel listings
Google Hotels Search Scraper
Search hotel listings by destination and collect displayed starting prices, guest ratings and review counts. Returns up to 20 hotels from one search page.
Google Hotels Search Scraper — Starting Prices, Ratings & Reviews
Search public hotel and vacation-stay listings by destination. The Actor captures the property name, displayed starting price and currency, rating, review count, price label, and Google Hotels listing URL. It reads the first results page only and returns no more than 20 listings.
This is a destination-search snapshot, not a date-specific hotel availability API. There are no check-in, check-out, currency-selection, or pagination-cursor input fields. Starting prices are not confirmed nightly rates for your travel dates, not guaranteed total stay prices, and not checkout quotes. Use the returned listing link to review current booking context before making a decision.
Contents
- Capabilities and use cases
- Input
- Output fields
- Real dataset example
- Limits and coverage
- Run and export
- Pricing and outcome policy
- Usage tips and data quality
- Use with AI and MCP
- Support
- FAQ
- Related searches
- Related Actors
- Resources and disclaimer
- 中文说明
Capabilities and use cases
- Search a destination using the required
queryfield and an adult count for context. - Return up to the requested 1–20 listings from the first search page, without claiming exhaustive destination coverage.
- Keep
startingPrice,currency, and the fullpriceLabeltogether so a numeric amount does not lose its displayed starting-price qualification. - Capture optional guest rating and review count when the result card makes them available; no review text or reviewer profiles are returned.
- Return
hotelUrlfor manual follow-up on the public Google Hotels property page. - Provide a stable hashed
hotelIdsuitable as an opaque matching key in your own analysis. - Store flat fields in the overview and retain the complete record through JSON export.
Where it fits
Destination reconnaissance: create a quick first-page shortlist for a city or region. A shortlist is not a comprehensive hotel census and cannot be used to claim every property was examined.
Starting-price observation: compare displayed starting prices across snapshots made with the same destination and adult context. Do not label them “available for my dates” because this Actor has no date inputs.
Rating-based research: organize visible ratings and review counts for manual review while preserving missing values. Counts are aggregates, not a downloaded review corpus.
Travel planning preparation: follow hotelUrl to inspect actual date availability and terms yourself. The Actor does not book rooms or guarantee rate availability.
Dashboard prototyping: use the flat result columns and original price label to show a clearly qualified starting-price view, rather than a misleading checkout-price table.
Input
| Field | Type | Required / default | Description and limits |
|---|---|---|---|
query | string | Required | Trimmed destination; non-empty and at most 100 characters. City, region, or destination. |
adults | integer | 2 | Adult traveler count for search context, 1–16; not a date-specific occupancy quote. |
maxItems | integer | 20 | First-page result cap, 1–20. No later-page traversal or cursor. |
Example input
{"query": "Istanbul","adults": 2,"maxItems": 5}
Required fields have no automatic target substitute. Optional defaults are shown above; explicit integer limits should stay inside the supported range. Use the input form for the current schema rather than assuming extra JSON properties are meaningful.
Output fields
| Field | Type | Description |
|---|---|---|
hotelId | string | Stable hashed listing identifier; keep as opaque text. |
hotelName | string | Displayed property name, which may describe a hotel or vacation stay. |
location | string | Destination searched, not a promised exact street address. |
hotelUrl | string | Public Google Hotels property URL for manual review. |
startingPrice | number|null | Displayed starting-price amount; not a date-specific or final booking quote. |
currency | string|null | Displayed currency code; no selectable currency input or conversion guarantee. |
priceLabel | string | Public result price label retained for interpretation. |
rating | number|null | Displayed guest rating when available. |
reviewCount | integer|null | Displayed review total when available; review bodies are not included. |
Types describe the public record and its optional values, not a promise that every field is populated. The built overview selects a subset of these fields; full JSON is the source for complete inspection.
Real dataset example
This unchanged row was retrieved from a historical SUCCEEDED Apify run YzEEoVZvbz0dFOXIB, started 2026-09-29T18:38:26.494Z, dataset LosXCZ4a7kbSf3hmV. It is real output, not illustrative placeholder data. The run is historical and does not claim a new live execution of the latest build. Values may differ on a future run.
Historical input:
{"query": "Istanbul","adults": 2,"maxItems": 20}
Stored row:
{"rating": 4.2,"hotelId": "5aa702e71e68541aaf35","currency": "EUR","hotelUrl": "https://www.google.com/travel/hotels/entity/ChkQ8fOWsuW5roZEGg0vZy8xMXhjX193anAyEAI","location": "Istanbul","hotelName": "happy apart hotel istanbul - Superior Apartment","priceLabel": "Prices starting from €21, happy apart hotel istanbul - Superior Apartment","reviewCount": 8,"startingPrice": 21}
Limits and coverage
First search page only. Maximum 20 listings. No travel-date inputs and no cursor. maxItems accepts 1–20 and defaults to 20. adults accepts 1–16 and defaults to 2. query must be non-empty after trimming and no longer than 100 characters. Supplying undocumented checkIn, checkOut, start, offset, page, cursor, or currency properties does not enable those features.
The returned starting price is a displayed public search amount. It must not be re-labelled as a guaranteed nightly price for a requested date, a tax-inclusive final price, a room-type offer, or a confirmed available booking. Preserve priceLabel together with startingPrice and currency. The sample's EUR currency is an observed output, not evidence that all destinations return EUR or that a customer can choose currency through this Actor.
The first page may contain fewer than your requested maximum or a mixture of hotels and vacation stays. Search ordering and public presentation can change. There is no complete inventory promise, no further-page traversal, and no supported mechanism to retrieve page two by increasing maxItems. Repeating the same query does not prove you have covered additional pages.
Ratings and review totals are optional. Their absence should remain missing, not become an invented zero. The Actor does not return review bodies, reviewer identities, amenities lists, photos, map coordinates, detailed street addresses, booking-provider offer breakdowns, or cancellation terms. hotelUrl is the appropriate public link for your own manual verification of such booking context.
Starting-price research workflow
Choose an unambiguous destination and record exactly how you spelled it. Use the same adults and maxItems context in repeated runs. Each export should be labelled “first-page public search snapshot” rather than “all hotels” or “available rooms for my dates”. If a downstream dashboard has check-in/out controls, do not imply they affected this Actor: keep the date-specific planning step separate.
Store hotelId as opaque text and hotelUrl as the public navigation link. Do not reconstruct the URL from the hash or assume a property name is unique. location describes the search destination and should not be imported into a street-address column. A property title can include an apartment description; avoid forcing every row into a full-service hotel category without review.
Show the price label in your report alongside the numeric starting price and currency. Missing prices should appear as unavailable, not zero. Cross-currency sorting requires your own explicit conversion policy and conversion timestamp; the Actor does not promise that transformation. Ratings and review counts can support a shortlist but do not replace the current property's booking information.
For trend monitoring, distinguish a property absent from the first page from a property that no longer exists. A ranking change or a smaller first-page response is not proof of closure. Keep repeated runs linked to their exact datasets so an older observation remains auditable. Before booking or publishing a price claim, open the current hotelUrl and verify the actual dates, occupancy, provider terms, fees, and final offer.
Run and export
Start in Apify Console
Open this Actor's Store page and select Try for free or Run. Sign in to your own Apify account, enter the documented input fields, and start a small run before increasing the result limit. The Actor does not require a separate target-service API key or a target-site login. An Apify account is still needed to execute it on the platform. A platform trial does not change the Actor's documented result cap or make third-party content unrestricted.
When the run ends, open its default dataset. The overview table is a convenient presentation of selected columns; it is not a promise that every record has every value. Open the full JSON dataset when you need to distinguish an empty array from an absent value, preserve types, or inspect columns that are not in the overview. The Actor output links named results and fullJson point to the overview and complete dataset respectively. These links are storage locations, not extra columns inside each result.
Export as JSON for typed integrations. Use CSV or Excel for manual analysis and review how arrays and missing values are represented before importing into a spreadsheet. XML is also available through Apify dataset export. Keep the original JSON alongside a spreadsheet export when your workflow depends on numeric prices, arrays, or explicit null values. A table cell that looks blank is not sufficient evidence that extraction failed.
Three API examples
These examples use standard Apify REST endpoints. Set APIFY_TOKEN locally to your own Apify API token before running them. Do not paste the token into a ticket, screenshot, public repository, shared notebook, or chat prompt. All request URLs are double-quoted so shell variables expand correctly and query-string ampersands do not split the command. The examples use Bearer authentication rather than embedding secrets in URLs.
1. Start a run and wait briefly for its status. The returned run object includes id, status, defaultDatasetId, and defaultKeyValueStoreId. A response after waitForFinish=60 may still say RUNNING; HTTP success is not proof that the Actor has finished. Replace illustrative travel dates with a suitable future interval when applicable.
curl --fail-with-body --silent --show-error --request POST \"https://api.apify.com/v2/acts/myagizm~google-hotels-scraper/runs?waitForFinish=60" \--header "Authorization: Bearer ${APIFY_TOKEN}" \--header "Content-Type: application/json" \--data '{"query":"Istanbul","adults":2,"maxItems":5}'
2. Read the exact run's status. Set RUN_ID to the data.id returned by example 1. Repeat this GET at a sensible interval while the run is READY or RUNNING. Only proceed to interpret final coverage after a terminal status is reported. Do not start a second run merely because the first wait period elapsed.
curl --fail-with-body --silent --show-error \"https://api.apify.com/v2/actor-runs/${RUN_ID}" \--header "Authorization: Bearer ${APIFY_TOKEN}"
3. Download that run's full dataset. Set DATASET_ID to data.defaultDatasetId from the same run. This retrieves JSON rather than the overview projection. An empty JSON array is possible; inspect the run and its OUTPUT record before deciding whether it means an input problem, a confirmed empty search, or a genuine processing failure.
curl --fail-with-body --silent --show-error \"https://api.apify.com/v2/datasets/${DATASET_ID}/items?format=json&clean=true" \--header "Authorization: Bearer ${APIFY_TOKEN}"
You can read the reason for a handled empty outcome in Console under the run's default key-value store, record OUTPUT. The REST resource for that record is https://api.apify.com/v2/key-value-stores/{defaultKeyValueStoreId}/records/OUTPUT; authenticate with your own token just as above. Do not substitute a dataset ID for a key-value-store ID: the run exposes both and they serve different purposes.
Integration checklist
Store the run ID, submitted input, execution time, dataset ID, and final status in your own job record. Fetch data from that exact dataset instead of using a mutable “last run” reference when multiple jobs may overlap. Decide how your application represents an empty successful result, and keep that state separate from a failed job. Deduplicate across runs in your own destination if repeated snapshots should update existing records rather than append indefinitely. The Actor's per-run cap is not a cross-run database constraint.
Handle API authentication and permission errors at the client layer. An HTTP 401 from the Apify API means you should check your token; it is not a target search outcome. Avoid an unconditional retry loop that repeatedly launches billable successful runs. A bounded retry of a genuine transient failed request can be reasonable, but first confirm the original run's state. A client timeout can occur even while the original run continues on Apify.
Pricing and outcome policy
The pricing model is pay per event, with the stored dataset item as the result event. The current snapshot rate is $0.002392 per stored result, equivalent to $2.392000 per 1,000 stored results. Check the Actor's live Pricing tab for the rate applicable when you run it; platform pricing, plan terms, and any other account-level charges are governed by Apify. The quoted result rate is not a guarantee of a fixed total account invoice.
Request limits describe an upper bound, not a reservation of that many successful results. A requested maximum does not mean the search will find that many matches. Only stored result rows trigger the documented result event. A zero-row handled input error has zero result charges; a confirmed no-results outcome also has zero result charges. The absence of a result event should not be confused with an assertion about every possible platform or account fee.
Platform schema validation may reject malformed input before a run starts; the following policy applies to handled runtime input errors after a run is created.
Input errors finish SUCCEEDED with no results and no charge; see OUTPUT for the reason. Handled, explicitly classified missing-target or no-results outcomes likewise finish successfully with zero dataset rows and an explanatory OUTPUT record. The errorType vocabulary can include INPUT_ERROR or INVALID_INPUT, NOT_FOUND, and NO_RESULTS, depending on the Actor. Read the supplied message and hint rather than treating every SUCCEEDED run as a non-empty dataset.
Access denial, network interruptions, timeouts, and extraction/parsing faults are not silently re-labelled as a legitimate empty search. A genuine processing failure can remain FAILED. Do not interpret an unexplained empty response as proof that no matching public content exists. When there is partial verified delivery, review the run's notes and stored rows instead of assuming the requested cap was reached. For billing questions, share the exact run ID and the number of stored rows, not only a screenshot of the input limit.
Usage tips and data quality
- Keep comparable inputs together. Preserve the target, location wording, guest context, dates where supported, and result cap with each export. A later result may differ because the public page changed, not because an earlier row was incorrect.
- Use a small pilot. Validate that the returned fields fit your intended workflow before scheduling recurring jobs or requesting the maximum supported batch. Test the same export format that your production consumer will use.
- Treat optional fields explicitly. Preserve
null, empty text, and empty arrays instead of converting them all to zero. A missing price is not a free stay; a missing review count is not evidence of no reviews; an empty contact array means no value was captured for that category. - Retain raw values. Store the returned currency, displayed label, URL, and other context before normalizing data. Changes to formatting should happen in your downstream model, not by assuming all destinations or websites use the same conventions.
- Avoid unsupported controls. Adding undocumented dates, cookies, pagination tokens, filters, or other arbitrary JSON properties does not create a supported feature. Use only the input fields listed in this README and the Actor's current input form.
- Review before action. Public search cards and contact pages can be incomplete or outdated. Verify a booking decision or a contact action against the current public page; the Actor provides structured observations, not a commercial guarantee.
- Schedule deliberately. Apify saved tasks and schedules can reuse your chosen input, subject to your account's available features. Choose a cadence appropriate to the data, and review empty and failed runs separately rather than masking them in an aggregate success counter.
- Control retention. Export important results to your own authorized storage and apply your own retention policy. Run-associated datasets may be subject to your Apify account's retention settings; a historical example is not a promise of permanent storage availability.
Use with AI and MCP
This Actor can be used in an AI-assisted workflow through Apify's supported MCP tooling. Configure your MCP-capable client using the official Apify documentation and authenticate with your own Apify account. Tool names and setup details depend on the client and on the current Apify MCP server version; this README does not invent a dedicated tool name or claim that a target-site-specific MCP server is required.
A practical flow is: find this Actor by its Store identifier myagizm/google-hotels-scraper, inspect its current input schema, submit only supported fields, wait for the exact run to finish, and retrieve its dataset. Ask the assistant to cite the run and preserve the returned values when summarizing. Give it the destination or URL and the supported limits explicitly. Do not let an assistant infer unsupported search filters or convert starting/displayed prices into guaranteed checkout quotes.
An AI summary should keep missing values visible and distinguish a successful empty outcome from a transport failure. It should not manufacture records to reach the requested maximum or fill in prices, phone numbers, addresses, availability, or ratings that the dataset did not contain. Credentials belong in your client's secure configuration, not in a natural-language instruction or public output. MCP is an integration route to the Actor, not a broader data-collection permission or a way around the limits listed below.
Support
Use this Actor's Issues tab on Apify for reproducible problems and feature requests. Include the exact run ID, a minimal sanitized input, expected result, actual result, and whether you inspected the complete JSON dataset. For empty SUCCEEDED runs, quote the non-sensitive OUTPUT errorType, message, and hint if present. For access or timeout problems, provide the run's terminal status and relevant sanitized message.
Never share an Apify token, login cookie, password, private network URL, or unrelated personal information in a public issue. A successful historical sample helps explain the output shape; it does not prove that the same target still returns identical data today. Requests for extra result coverage or new fields are feature requests, not commitments that the current version supports them. Existing limits remain in force until the input schema and documentation explicitly change.
Related Actors
Use these separate Actors when they match your task. They are not automatic stages of this Actor, and running a sibling can have its own input requirements and charges.
Resources and disclaimer
- Actor Store page: current input form, pricing, runs, and Issues.
- Apify documentation: Console, tasks, schedules, storage, and integrations.
- Apify API reference: authentication, run status, dataset export, and key-value-store records.
- Apify MCP documentation: current supported MCP setup.
This Actor is an independent data-collection utility, not an endorsement, booking service, contact verification service, or official product of the websites named in its title or examples. Trademarks belong to their respective owners. Public visibility does not remove privacy obligations, website terms, content rights, or restrictions on reuse. You are responsible for ensuring that your collection, storage, analysis, outreach, and republication are lawful and authorized.
Do not use the Actor to bypass authentication or access restrictions, conduct unlawful spam campaigns, or make unsupported claims about people or properties. Returned data is an observation of public content at run time and can become outdated. Confirm important decisions using the current relevant page. The example below is a real historical dataset row, not a guarantee of present availability, an instruction to contact the listed people, or permission to reuse content beyond applicable rights.
FAQ
1. Can I provide check-in and check-out dates?
No. The current input schema has only query, adults, and maxItems. Starting prices are not date-specific booking quotes.
2. Can I request page two with a cursor?
No. The Actor reads the first page only and exposes no cursor, page, or offset input.
3. What is the maximum number of results?
20 first-page listings. A larger maxItems is unsupported and does not unlock additional coverage.
4. Is startingPrice a final booking price?
No. It is the public starting amount; verify dates, occupancy, fees, and terms on the current listing.
5. Can I select a currency?
No. There is no currency input. Preserve the currency actually returned and handle any conversion downstream.
6. Are all results conventional hotels?
Not necessarily. Public results can include vacation stays or apartments; review the property title.
7. Does location contain a street address?
No. It is destination context, not a guaranteed exact property address.
8. Can I get individual guest reviews?
No. reviewCount is an aggregate count; review text and reviewer data are outside this output.
9. Is hotelId the native Google identifier?
It is a stable hashed listing identifier. Treat it as opaque and use hotelUrl for navigation.
10. Does absence from a later run mean a property closed?
No. A first-page snapshot is bounded and rankings can change. Absence is not a verified closure signal.
11. Do I need a target-site account or separate API key?
No target-site login or separate target-service key is required for the documented public data. Apify execution and API calls still use your own Apify account and API token.
12. Why did SUCCEEDED return an empty dataset?
Handled input errors and explicitly classified missing or empty outcomes can succeed with zero rows. Read OUTPUT for the errorType, message, and hint; success is not a non-empty-data guarantee.
13. Are handled invalid inputs billed?
No result rows are stored and no result event is charged for the handled input-error outcome. Consult Apify separately for platform and account billing terms.
14. Will every genuine processing error also say SUCCEEDED?
No. Access denial, network, timeout, and parsing faults can remain FAILED. They must not be confused with a confirmed legitimate no-results outcome.
15. Is the requested maximum guaranteed?
No. It is an upper limit. Public content availability, bounded coverage, optional fields, and execution constraints can yield fewer rows.
16. Can I export CSV or Excel?
Yes, using Apify dataset export. Keep JSON when arrays, null values, or numeric types matter, and check how your spreadsheet handles those values.
17. Why is a field not visible in the overview table?
The table is a selected-field view. Read the full JSON dataset before concluding that a field was not returned, and preserve optional missing values as missing.
18. Can I use schedules and saved tasks?
You can use Apify platform tasks and scheduling features available to your account. Reuse valid inputs and review changes, empty outcomes, and pricing before running repeatedly.
19. What should I include in a support request?
The exact run ID, sanitized input, actual versus expected output, final status, and non-sensitive OUTPUT explanation. Never include API tokens or private credentials.
20. May an AI assistant fill missing values or infer unsupported fields?
No. Ask it to summarize actual rows, preserve missing values, and respect the exact schema. MCP access does not add features or permission to bypass limits.
Related searches
Google Hotels scraper, destination hotel search, hotel starting prices, hotel ratings and review counts, first-page accommodation dataset, public hotel price snapshot. These terms describe supported research contexts, not additional input fields or a promise of broader coverage.
中文说明
Google 酒店搜索 — 起始价格、评分与评论数
按目的地搜索公开酒店和度假住宿列表。Actor 捕获物业名称、展示的起始价格和币种、评分、评论数、价格标签及 Google 酒店房源 URL。只读取第一页,最多返回 20 条。
这是目的地搜索快照,不是指定日期房态 API。没有入住、退房、币种选择或分页游标输入。起始价格不是你的旅行日期的确认每晚价,不是保证住宿总价,也不是结算报价。作决策前应使用返回的房源链接查看当前预订上下文。
中文目录
能力与用途
- 使用必填
query按目的地搜索,成人数量提供搜索上下文。 - 从第一页返回请求的 1–20 条上限,不承诺目的地全量覆盖。
- 同时保留
startingPrice、currency与完整priceLabel,避免数字脱离其“起始价格”限定。 - 返回卡片可见的可选评分和评论总数,不返回评论正文或评论者资料。
- 返回
hotelUrl,便于人工到公开 Google 酒店物业页继续确认。 - 提供稳定哈希
hotelId,可在自己的分析中作为不透明匹配键。 - 概览使用平铺字段,JSON 导出保留完整记录。
适用场景
目的地初步研究: 为城市或地区建立第一页候选清单。候选清单不是完整酒店普查,不能据此声称检查了所有物业。
起始价格观察: 比较相同目的地和成人上下文的重复快照。不能标成“我的日期可订价格”,因为本 Actor 没有日期输入。
评分研究: 整理可见评分与评论数,并保留缺失值。评论数是汇总数字,不是下载的评论语料。
旅行规划准备: 使用 hotelUrl 人工检查真实日期房态和条款。Actor 不预订房间,也不保证价格可获得。
仪表盘原型: 使用平铺字段和原价格标签展示明确限定的起始价格,不做误导性结算价表。
输入字段
| 字段 | 类型 | 必填 / 默认值 | 说明与限制 |
|---|---|---|---|
query | string | 必填 | 去除首尾空格的目的地,非空且最多 100 字符;城市、地区或目的地。 |
adults | integer | 2 | 搜索上下文的成人数,1–16;不是指定日期入住报价。 |
maxItems | integer | 20 | 第一页结果上限,1–20;不遍历后续页,也没有游标。 |
输入示例
{"query": "Istanbul","adults": 2,"maxItems": 5}
必填字段没有自动替代目标;可选默认值如上。显式整数限制必须位于支持范围内。当前输入结构以表单为准,不要假设额外 JSON 属性有意义。
输出字段
| 字段 | 类型 | 说明 |
|---|---|---|
hotelId | string | 稳定哈希房源标识,应保留为不透明文本。 |
hotelName | string | 展示的物业名称,可能是酒店或度假住宿。 |
location | string | 搜索目的地,不是保证的完整街道地址。 |
hotelUrl | string | 供人工复核的公开 Google 酒店物业 URL。 |
startingPrice | number|null | 展示的起始金额,不是指定日期或最终预订报价。 |
currency | string|null | 展示的币种代码;没有可选币种输入或转换保证。 |
priceLabel | string | 保留的公开结果价格标签,供正确解释。 |
rating | number|null | 可获得时的展示住客评分。 |
reviewCount | integer|null | 可获得时的展示评论总数,不含评论正文。 |
类型描述公开记录及可选值,不保证每个字段都填满。构建中的概览选择部分字段;需要完整检查时应读取全部 JSON。
真实数据集样例
以下行原样读取自历史 SUCCEEDED Apify 运行 YzEEoVZvbz0dFOXIB,启动时间 2026-09-29T18:38:26.494Z,数据集 LosXCZ4a7kbSf3hmV。它是真实输出,不是占位演示。此证据属于历史运行,不声称刚刚对最新构建执行了新测试;未来运行的值可能变化。
历史输入:
{"query": "Istanbul","adults": 2,"maxItems": 20}
已存储数据行:
{"rating": 4.2,"hotelId": "5aa702e71e68541aaf35","currency": "EUR","hotelUrl": "https://www.google.com/travel/hotels/entity/ChkQ8fOWsuW5roZEGg0vZy8xMXhjX193anAyEAI","location": "Istanbul","hotelName": "happy apart hotel istanbul - Superior Apartment","priceLabel": "Prices starting from €21, happy apart hotel istanbul - Superior Apartment","reviewCount": 8,"startingPrice": 21}
限制与覆盖
只读第一页,最多 20 条,没有旅行日期输入,也没有游标。 maxItems 支持 1–20,默认 20;adults 支持 1–16,默认 2;query 去除首尾空格后必须非空且不超过 100 字符。提交未记录的 checkIn、checkOut、start、offset、page、cursor 或 currency 属性,不会启用这些功能。
返回的起始价格是公开搜索展示金额,不能改写成指定日期的保证每晚价、含税最终价、某种房型报价或已确认可预订价格。应将 priceLabel、startingPrice 和 currency 一起保留。样例中的 EUR 是观察到的输出,不代表所有目的地都返回 EUR,也不说明客户可在本 Actor 中选择币种。
第一页可能少于请求上限,也可能同时包含酒店和度假住宿。排序和公开呈现方式可能变化。不保证完整库存,不遍历后续页,也不能通过增大 maxItems 获取第二页。重复同一个 query 不证明覆盖了额外页面。
评分和评论总数为可选值,缺失时不能编造成零。不会返回评论正文、评论者身份、设施清单、照片、地图坐标、详细街道地址、不同预订平台的报价明细或取消条款。需要这些预订上下文时,应使用 hotelUrl 人工查看当前公开页面。
起始价格研究流程
选择明确目的地,并记录实际写法。重复运行保持 adults 与 maxItems 相同。每次导出应标成“公开搜索第一页快照”,而不是“全部酒店”或“我的日期可住房间”。若下游仪表盘有入住退房控件,不能暗示它们影响了本 Actor;指定日期规划应作为独立步骤。
将 hotelId 存成不透明文本,将 hotelUrl 用作公开导航链接,不要从哈希重构地址,也不要假设名称唯一。location 是搜索目的地,不应导入完整街道地址列。物业名称可能含公寓描述,不应未经复核把所有记录归为全服务酒店。
报表应把价格标签、起始数值和币种一起展示。缺失价格应显示不可获得,不是零。跨币种排序需要自己的明确换算规则和汇率时间,Actor 不承诺这一变换。评分和评论数可辅助候选筛选,但不能替代当前预订信息。
趋势监测中,应区分“没出现在第一页”与“物业已不存在”。排序变化或较短第一页响应不能证明停业。每次运行关联准确数据集,以便审计旧观察。预订或发布价格结论前,应打开当前 hotelUrl,核查实际日期、人数、预订方条款、费用和最终报价。
运行与导出
在 Apify 控制台启动
打开本 Actor 的商店页面,选择 Try for free 或 Run,登录自己的 Apify 账户,填写本文列出的输入字段。首次运行建议使用较小的结果上限,确认数据适合你的工作流程后再扩大请求。本 Actor 不要求另行提供目标服务的 API 密钥,也不要求目标网站登录信息;但在 Apify 平台执行仍然需要 Apify 账户。平台试用资格不会改变本文的结果限制,也不会使第三方内容变成可无限制使用的数据。
运行结束后,打开该次运行的默认数据集。overview 表格只是部分字段的便捷展示,并不保证每条记录的所有字段都有值。需要区分空数组与缺失值、保留类型或检查未展示字段时,请查看完整 JSON。Actor 输出中的 results 和 fullJson 分别指向概览与完整数据集;它们是存储链接,不是每条结果中的额外数据列。
需要保留类型时,优先导出 JSON。手动分析可以使用 CSV 或 Excel,但应先确认数组和缺失值在导出后如何表示。Apify 也支持 XML 数据集导出。若后续逻辑依赖价格数值、数组或明确的 null,请在电子表格之外保留原始 JSON。表格中的空白单元格本身不能证明抓取失败。
三个 API 示例
下面使用标准 Apify REST API。运行前,请在本地将 APIFY_TOKEN 设置为自己的 Apify API 令牌。不要将真实令牌放进工单、截图、公开代码库、共享笔记或聊天提示。请求 URL 使用双引号,确保 shell 变量展开,并避免查询参数中的 & 拆分命令。认证通过 Bearer 请求头完成,而不是将凭据嵌入 URL。
1. 启动运行并短暂等待状态。 返回的运行对象包含 id、status、defaultDatasetId 和 defaultKeyValueStoreId。即使设置 waitForFinish=60,返回时也可能仍为 RUNNING;HTTP 成功不等于 Actor 已经执行完毕。住宿日期示例仅供说明,实际运行时应换成合适的未来日期。
curl --fail-with-body --silent --show-error --request POST \"https://api.apify.com/v2/acts/myagizm~google-hotels-scraper/runs?waitForFinish=60" \--header "Authorization: Bearer ${APIFY_TOKEN}" \--header "Content-Type: application/json" \--data '{"query":"Istanbul","adults":2,"maxItems":5}'
2. 查询这一条运行的状态。 将 RUN_ID 设置为第一步返回的 data.id。当状态为 READY 或 RUNNING 时,以合理间隔重复查询;只有收到终态后,才判断最终覆盖范围。不要仅因为等待时间结束就再启动一次运行。
curl --fail-with-body --silent --show-error \"https://api.apify.com/v2/actor-runs/${RUN_ID}" \--header "Authorization: Bearer ${APIFY_TOKEN}"
3. 下载同一次运行的完整数据集。 将 DATASET_ID 设置为该运行的 data.defaultDatasetId。此命令返回完整 JSON,而不是概览投影。响应可能为空数组;请结合运行状态和 OUTPUT 记录,判断是输入问题、已确认的空搜索,还是实际处理故障。
curl --fail-with-body --silent --show-error \"https://api.apify.com/v2/datasets/${DATASET_ID}/items?format=json&clean=true" \--header "Authorization: Bearer ${APIFY_TOKEN}"
对于已处理的空结果,可在控制台中打开该次运行的默认键值存储并查看 OUTPUT 记录。对应的 REST 地址格式为 https://api.apify.com/v2/key-value-stores/{defaultKeyValueStoreId}/records/OUTPUT,认证方式与上面相同。请不要把数据集 ID 当成键值存储 ID;运行对象同时提供两者,但用途不同。
接入检查清单
在自己的任务记录中保存运行 ID、提交的输入、执行时间、数据集 ID 和最终状态。多个任务可能重叠时,应读取准确的数据集,不要使用可变化的“最后一次运行”引用。业务系统应把成功但为空的结果与失败任务分开处理。如果重复快照应该更新已有记录,而不是不断追加,请在自己的目标库中执行跨运行去重。本 Actor 的单次结果上限不是跨运行数据库约束。
Apify API 的认证与权限问题应在客户端处理。例如 API 返回 HTTP 401,应检查自己的令牌,而不是把它解释成目标搜索无结果。避免无条件重试并反复创建可计费的成功运行。遇到真实瞬时故障可以有限重试,但先确认原运行状态;客户端超时并不意味着 Apify 上的原运行已停止。
价格与结果状态
本 Actor 采用 按事件计费,已写入数据集的结果行是结果事件。当前价格快照为 每条已存储结果 $0.002392,即 每 1,000 条 $2.392000。实际运行前请查看商店的实时 Pricing 页面;平台价格、账户计划及其他账户级费用由 Apify 管理。这里的结果单价不承诺账户总账单固定不变。
请求上限只是最多可返回的数量,不表示预先保留了相同数量的成功结果,也不保证能够找到那么多匹配项。只有已存储结果行触发本文说明的结果事件。已处理的输入错误为零行、零结果费用;已确认的无结果情况也不产生结果费用。没有结果事件,不等于对所有可能的平台或账户费用作出承诺。
平台输入架构验证可能在创建运行之前拒绝格式错误的输入;以下策略适用于创建运行之后由 Actor 处理的输入错误。
输入错误会以 SUCCEEDED 状态结束,无结果且不收费;原因请查看 OUTPUT。 被明确分类并处理的目标不存在或无搜索结果情况,同样以成功状态结束,数据集为零行,并提供 OUTPUT 说明。不同 Actor 的 errorType 可能使用 INPUT_ERROR 或 INVALID_INPUT、NOT_FOUND、NO_RESULTS。请读取返回的 message 和 hint,不要把每次 SUCCEEDED 都当成必然有数据。
访问拒绝、网络中断、超时以及提取或解析故障,不会被悄悄改写成正常的空搜索。真实处理故障可能仍为 FAILED。没有明确说明的空响应不能证明公开内容确实没有匹配项。若已返回部分经过验证的数据,应检查运行备注和实际行数,不要假定达到了请求上限。咨询计费时,请提供准确运行 ID 和已存储行数,而不是仅提供输入上限截图。
使用建议与数据质量
- 保留可比较的输入。 每次导出都记录目标、目的地写法、成人数量、受支持的日期和结果上限。后续结果不同,可能是公开页面变化,不代表之前的记录一定错误。
- 先小规模试用。 在设置定时任务或请求最大批次前,确认字段符合实际需求,并测试生产系统将使用的导出格式。
- 显式处理可选字段。 不要把
null、空文本和空数组全部转换为零。价格缺失不代表免费住宿;评论数缺失不代表没有评论;某个联系方式数组为空,只代表该类值未被捕获。 - 保存原始值。 在规范化之前,先保留币种、展示标签、URL 和上下文。不要假设所有目的地与网站使用相同格式。
- 不要添加未支持的控制项。 在 JSON 中加入未记录的日期、Cookie、分页令牌、筛选项或其他属性,并不会自动得到对应功能。只使用本文和当前输入表单列出的字段。
- 行动前复核。 搜索卡片和联系页面可能不完整或已过期。预订和联系行动应以当前公开页面为准;本 Actor 返回结构化观察结果,而不是商业保证。
- 合理安排周期。 Apify 保存任务和定时功能可复用输入,具体取决于账户支持的功能。应选择与数据变化相符的周期,并分别处理空运行和失败运行,不要用单一成功率掩盖两者差别。
- 控制留存。 重要结果应导出到自己的授权存储,并遵守自己的保留策略。运行关联数据集可能受 Apify 账户留存设置影响;历史样例不意味着存储永久可用。
AI 与 MCP 使用方式
本 Actor 可通过 Apify 支持的 MCP 工具接入 AI 辅助流程。请按照 Apify 官方文档配置支持 MCP 的客户端,并使用自己的 Apify 账户认证。工具名称和设置方法取决于客户端及当前 Apify MCP 服务器版本;本文不会虚构专用工具名,也不会声称需要目标网站专属 MCP 服务器。
推荐流程:按商店标识 myagizm/google-hotels-scraper 找到 Actor,检查当前输入结构,仅提交支持的字段,等待准确的运行结束,再读取其数据集。让助手在总结中注明运行并保留真实返回值,明确告诉它目标 URL 或目的地和结果上限。不要让助手推断未支持的筛选项,也不要把起始价格或展示价格改写成保证结算报价。
AI 总结应保留缺失值,并区分成功空结果与传输故障。它不应为了达到请求数量而编造记录,也不应填入数据集中没有的价格、电话号码、地址、房态或评分。凭据应放在客户端安全配置中,而不是自然语言指令或公开输出中。MCP 是调用 Actor 的接入方式,不是扩大采集权限或绕过产品限制的方法。
支持
可在本 Actor 的 Apify Issues 页面提交可复现问题或功能需求。请提供准确运行 ID、最小化且已脱敏的输入、预期结果、实际结果,以及是否检查过完整 JSON。对于空的 SUCCEEDED 运行,可引用非敏感 OUTPUT 中的 errorType、message 和 hint。访问或超时问题应附上运行终态和相关脱敏消息。
不要在公开工单中分享 Apify 令牌、登录 Cookie、密码、私有网络 URL 或无关个人信息。历史成功样例用于说明数据结构,并不能证明同一目标今天仍返回相同数据。扩大覆盖或新增字段属于功能请求,不代表当前版本已经支持;除非输入结构和文档明确改变,否则现有限制继续适用。
相关 Actors
以下是独立 Actor,适用时可单独选择。它们不是本 Actor 自动执行的步骤,分别运行可能有自己的输入要求和费用。
资源与免责声明
- Actor 商店页面:当前输入表单、价格、运行与 Issues。
- Apify 文档:控制台、任务、定时、存储与集成。
- Apify API 参考:认证、状态查询、数据集导出与键值记录。
- Apify MCP 文档:当前受支持的 MCP 配置方法。
本 Actor 是独立的数据采集工具,不是所述网站的官方产品、背书、预订服务或联系方式验证服务。商标归各自所有者所有。公开可见并不免除隐私义务、网站条款、内容权利和再次使用的限制。你应确保采集、存储、分析、联系和再发布行为合法且获得必要授权。
请勿用于绕过认证和访问限制、实施违法垃圾信息活动,或对个人与住宿作出数据不支持的结论。返回数据是运行时的公开内容观察,之后可能过期;重要决策应再次检查当前页面。下方样例是真实历史数据行,不保证现在仍有房态,不构成联系其中人员的指令,也不授予超出适用权利范围的内容使用许可。
常见问题
1. 能提供入住退房日期吗?
不能。当前只有 query、adults、maxItems,起始价格不是指定日期报价。
2. 能用游标获取第二页吗?
不能。只读取第一页,没有 cursor、page 或 offset 输入。
3. 最多多少条?
第一页最多 20 条,增大 maxItems 不受支持,也不会扩展覆盖。
4. startingPrice 是最终价吗?
不是。它是公开起始金额,应在当前房源确认日期、人数、费用和条款。
5. 能选择币种吗?
不能。没有 currency 输入,应保留真实返回币种,换算在下游处理。
6. 结果全是传统酒店吗?
不一定。公开结果可能有度假住宿或公寓,应复核名称。
7. location 是街道地址吗?
不是。它表示目的地上下文,不保证是物业完整地址。
8. 能获取逐条评论吗?
不能。reviewCount 是汇总数量,不返回评论正文或评论者资料。
9. hotelId 是原生 Google ID 吗?
它是稳定哈希标识,应作为不透明值,导航使用 hotelUrl。
10. 后续运行没出现就是停业吗?
不是。第一页快照有限且排序会变,缺席不是确认停业信号。
11. 需要目标网站账户或另外的 API 密钥吗?
本文公开数据无需目标网站登录或另外的目标服务密钥;Apify 执行和 API 调用仍使用你自己的 Apify 账户与令牌。
12. 为什么 SUCCEEDED 但数据为空?
已处理的输入错误或明确分类的缺失、空结果可成功结束且为零行。请看 OUTPUT 的 errorType、message、hint;成功不保证非空。
13. 已处理无效输入会计费吗?
不会保存结果行或触发结果事件;平台与账户费用条款应另查 Apify。
14. 真实处理故障也会显示 SUCCEEDED 吗?
不会。访问拒绝、网络、超时、解析问题可能为 FAILED,不应与已确认的正常无结果混淆。
15. 请求最大值一定返回吗?
不一定。它是上限,公开内容、有限覆盖、可选字段和执行约束可能使行数更少。
16. 可以导出 CSV 或 Excel 吗?
可以,通过 Apify 数据集导出。数组、null 或数字类型重要时也保留 JSON,并检查表格如何处理这些值。
17. 为什么概览看不到某字段?
概览是选定字段视图。判断字段未返回前应查看完整 JSON,同时保持可选缺失值为缺失。
18. 能用定时和保存任务吗?
可使用账户支持的 Apify 任务与定时功能;复用有效输入,并在反复运行前检查变化、空结果与价格。
19. 支持请求需要什么?
准确运行 ID、脱敏输入、实际与预期输出、终态和非敏感 OUTPUT 说明;不要附 API 令牌或私有凭据。
20. AI 可以补齐缺失值或推断未支持字段吗?
不能。应总结真实数据、保留缺失值并遵循准确结构;MCP 接入不会增加功能或绕过限制的权限。
相关搜索
Google 酒店抓取、目的地酒店搜索、酒店起始价格、酒店评分与评论数、第一页住宿数据集、公开酒店价格快照。这些关键词描述受支持的研究场景,不是额外输入字段,也不保证更广覆盖。