5. Web Data, APIs and Google Sheets
5.3 Many Pages: Pagination with a Parameter and a Custom Function
Start with a problem
A partner API returns dark stores 2 per page. Ravina's query reads only page 1 and misses stores.
Explain simply
Build a query for one page, turn the page number into a parameter, convert the query into a function, then call the function for a list of page numbers and expand.
Show the data
Practice pages (JSON on this course site):
| File | Stores |
|---|---|
| web_darkstores_page_1.json | S01 Kothrud (Pune), S02 Baner (Pune) |
| web_darkstores_page_2.json | S03 Gangapur (Nashik), S04 College Road (Nashik) |
| web_darkstores_page_3.json | S05 Rajarampuri (Kolhapur) |
About this data: This table uses columns: File, Stores. This table uses columns: Page 1 query. This table uses columns: Page. Values shown are the lesson examples already on this page (not a new dataset).
Fictional sample data. Practice file: web_darkstores_page_1.json, web_darkstores_page_2.json, web_darkstores_page_3.json (source: src/practice/).
Demonstrate
- Copy the link of page 1. Create a Text parameter
BaseUrlwith everything beforeweb_darkstores_page_1.json. -
Manage Parameters › New ›
PageNo, Decimal Number, current 1. Blank query:Json.Document(Web.Contents(BaseUrl, [RelativePath = "web_darkstores_page_" & Text.From(PageNo) & ".json"]))[stores]› To Table › expand.Your result should look like this:
Page 1 query 2 rows: S01, S02 -
Right-click the query › Create Function… ›
fnGetStoresPage. -
New blank query
= {1..3}› To Table › rename columnPage› Whole Number.Your result should look like this:
Page 1, 2, 3 -
Add Column › Invoke Custom Function › fnGetStoresPage, PageNo = Page › expand.
Your result should look like this:
storeId store city S01 Kothrud Pune S02 Baner Pune S03 Gangapur Nashik S04 College Road Nashik S05 Rajarampuri Kolhapur
Show the result
Your result should look like this (fictional sample):
| Page | Rows |
|---|---|
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
| Total | 5 |
Explain what happened
The function wrapped the one-page logic; invoking it on the Page list ran it three times and stacked the results. The base URL stayed fixed and only RelativePath changed, which keeps Service refresh possible.
Explore further
- Each page also returns
pageCount(3). Use it to build the list:{1..Json.Document(...)[pageCount]}instead of hard-coding 3.
Detailed reference for this lesson:
Some sites or APIs show data page by page: …/stores?page=1, …/stores?page=2 … Build one query for a single page, turn it into a function, and call it for a list of page numbers.
Steps in Power BI
- Build a query for page 1 and clean it fully (for example a fictional partner site
https://example.com/darkstores?page=1). - Home › Manage Parameters › New Parameter › Name
PageNo› Type Decimal Number › Current Value1. - Open Home › Advanced Editor and replace the hard-coded
1in the URL with the parameter (see the code below). - Right-click the query in the Queries pane › Create Function… › name it
fnGetStoresPage. Power Query links the function to the query, so editing the query updates the function. - Home › New Source › Blank Query and type
= {1..5}(a list of pages) › To Table (List Tools › Transform) › rename the column to Page › set type to Whole Number. - Add Column › Invoke Custom Function › Function query
fnGetStoresPage› PageNo = column Page › OK. - Click the expand icon on the new column to expand all columns. You now have all pages in one table.
// fnGetStoresPage
(PageNo as number) as table =>
let
Source = Web.Contents("https://example.com",
[RelativePath = "darkstores", Query = [page = Text.From(PageNo)]]),
Page = Html.Table(Text.FromBinary(Source), {{"Store", ".store-name"}, {"City", ".store-city"}},
[RowSelector = ".store-card"])
in
Page
Keep the base URL fixed for Service refresh
Write Web.Contents("https://example.com", [RelativePath = …, Query = […]]) instead of joining the whole URL as text ("https://example.com/darkstores?page=" & Text.From(PageNo)). The Power BI Service must be able to see the base URL to validate a dynamic data source. Otherwise scheduled refresh can fail with a message that the dataset contains dynamic data sources.
Practice task
Convert a one-page query into a function and load pages 1–3. Then make the last page number a parameter MaxPage and use {1..MaxPage}.
Ravindra Bagale's Tip
Friends, many students write a custom function for pagination but invoke it on hard-coded page numbers, so new pages never appear. Generate the page list dynamically (for example {1..PageCount}) and test with two or three pages first before loading everything. Add a small delay or limit the number of requests to respect the website. This matters for both exams and interviews.
Ravindra Bagale's Tip – मराठी
मित्रांनो, बरेच students pagination साठी custom function लिहितात पण ते hard-coded page numbers वर invoke करतात, त्यामुळे नवीन pages कधीच येत नाहीत. Page list dynamically तयार करा (उदाहरणार्थ {1..PageCount}) आणि सगळं load करण्याआधी दोन-तीन pages वर test करा. Website चा आदर राखण्यासाठी छोटा delay ठेवा किंवा requests ची संख्या मर्यादित करा. हे exam आणि interview दोन्हीसाठी important आहे.
Ravindra Bagale's Tip – हिंदी
दोस्तों, बहुत से students pagination के लिए custom function लिखते हैं पर उसे hard-coded page numbers पर invoke करते हैं, तो नए pages कभी नहीं आते. Page list dynamically बनाओ (जैसे {1..PageCount}) और सब load करने से पहले दो-तीन pages पर test करो. Website का सम्मान करने के लिए थोड़ा delay रखो या requests की संख्या सीमित करो. यह exam और interview दोनों के लिए ज़रूरी है.
Fix common mistakes
| Wrong result | Reason | Correction |
|---|---|---|
| New page 4 never appears | Page list hard-coded as | Build the list from pageCount |
| Refresh fails in the Service: dynamic data source | Whole URL built by joining text | Static base URL + RelativePath |
| Function error on page 3 | Expanded fields assumed 2 rows | Expand by column names, not positions |
Practise independently
Practice task
Count stores by city from the combined table.
Hints
- 5 rows in total.
Solution
Pune 2, Nashik 2, Kolhapur 1.
Think like a professional
Respect API page sizes and rate limits; fetch only the pages you need and log the row count each refresh.
Revision card