Адаптаванне закрытых цэн па адваротным аналізе запытак API у фоне
Знайце цены, які ніколі не показуюцца ў HTML, стежачы за DevTools за запытамі XHR, REST і GraphQL, які відбуваюцца на адзінцы стороніцы, а потым перзапускаючы гэтыя запыты безпосередня.
Другі частка серыі "Як на самай працоўвае скрапінг"
У паканальный стацыяні мы зішлі на перакананне: інодзе цена, якая нам патрэбна, проста не існуе ў жадным з фрагментаў HTML, якія запрашвае requests. Яна не ўкладзена ў JSON-LD, не знаходзіцца ў таге meta, яе проста няма. Але гэта не значыць, што мы застряглі — зазвычай гэта проста означае, што стораніца запрашвае гэтыя даны пасля пачатковага завантажэння, чераз аднальны фонавы запыт. Мацель тут — знайсці гэты запыт і адрабатваць яго самім.
Крок 1: Ачыніце вкладку "Сеть"
Мы будзем працаваць на конкрэтным прыкладзе: стораніцы товара на сайте Target, target.com/p/dyson-ball-animal-3-upright-vacuum/-/A-85269291 (гэта толькі для деманстрацыі — той самы падход працюе на практычна будзь-якай стораніцы товара).
- Завантажыце будзь-якую стораніцу товара.
F12). Шаг 2: Знайсці запит, які вам действительна трэба
Пройдзіце па спісе аднае ентры за іншай, клацаючы на кожную і пераканаліваючыся ў панелі Response або Preview справа. Вы шукаеце JSON-данні, якія маюць цену, колькасць адзінакоў або будзь-яе іншае значэнне, якое вам трэба.
Є шырэйшы спосаб: выкорыстайце падзелку пошуку у виглядзе лупы, якая знаходзіцца ў вікні «Сеть», і увайсце значэнне, якое ўжо відразу видна на самай сторанцы. У прыкладзе з Target, якщо увайсці «449.99», то будзе адразу выкананы запит типу POST пад назвай deferred_enrichment/modules. Його тэла-адказ ёсць большым об’ектам JSON, і ў яго ўнутрошчы вы знайдзеце "formatted_current_price":"$449.99.
Шаг 3: Адтворыце цей запит самі
Выберыце гэты запит і зафіксавайце ўсю його URL. У гэтым случае це запит типу POST, але всё неабходнае ўжо є ў строе запита:
https://www.target.com/cdui_orchestrations/v1/pages/pdp/deferred_enrichment/modules
?tcin=85269291
&key=9f36aeafbe60771e321a7cc95a78140772ab3e96
&channel=WEB
&device_type=DESKTOP
Ось як гэта выглядае, калі адтворваць на Python:
import requests
url = "https://www.target.com/cdui_orchestrations/v1/pages/pdp/deferred_enrichment/modules"
params = {
"tcin": "85269291", # the product ID, from the page URL
"key": "9f36aeafbe60771e321a7cc95a78140772ab3e96",
"channel": "WEB",
"device_type": "DESKTOP",
}
resp = requests.post(url, params=params, headers={"User-Agent": "Mozilla/5.0"})
data = resp.json()
price = data["modules"][0]["module_data"]["data"]["product"]["price"]["formatted_current_price"]
print(price) # $449.99
Гэта і є весь секрет. Няма ніякіх бібліятэкаў для парсінгу, няма CSS-селектараў — вы проста адправляеце той самы запит, які ў тылу адправляе JavaScript сторанцы.
Парадакт: у DevTools правайм клікніце на запит і выберыце Copy → Copy as cURL. Чыгульна гэта дае вам точныя заголовкі і кукі, якія дадзены браузерам, і якія можна перакласты ў такі кліент, як Postman, або пераканваліць у Python, каб з’ясаваць, які саме элементы насправды неабходны.
Шаг 4: Калі API ў формате GraphQL
Дзеяныя сайты направляюць усё через GraphQL замест традыцыйнага REST-рэштрыктування. Гэты формат можна распазнакаць таму, што кожны запыт падходзіць да та самага канцачнага пункту (часта /graphql), а фактычны запыт належыць у тэле запыту, а не ў URL:
{
"operationName": "GetPrice",
"variables": { "productId": "12345" },
"query": "query GetPrice($productId: ID!) { product(id: $productId) { price } }"
}
Дзеяныя сайты ідуць даўжэй, выкарыстоўваючы persisted query — у такім случае кліент адправляе не весь текст запыту, а толькі короткі хэш, який яго заменяе:
/graphql/GetPrice/a1b2c3d4e5f6...?variables={"productId":"12345"}
Этот хэш нельзя вырахаваць самастае — яго трэба заўсёды браць безпасова з DevTools. А так как ён прыязначаны для фронтэнд-часткі сайту, будь-яе апдэйт на ўсунуці можа зменіць хэш і тыха паспрабаваць зламаць ваш скрыпт. Гэта справжня постаяла цена адвароту на гэты метод.
Шаг 5: Перакананне, чы рэальна ключ API є прыватным
Зноў паглядзіце на URL-адрэсу з Шага 3 — заўважыце, што key=9f36aeafbe60771e321a7cc95a78140772ab3e96 відкрыта належыць у строке запиту. Чы гэта тое, да чаго вам не павінна быць даступнае?
Зазвычай ні. Найшырэйшы спосаб працавання — адкрыць View Page Source (Ctrl+U), а потым знайсці apiKey за дапамою Ctrl+F. Вы пабачыце той самы ключ у чыстам тексте, ў блоке налашчэння, які Target адправляе кожнаму візітару.
Якщо значэнне вже знаходзіцца ў сабеўскай маркапэйнг-структуре стораніцы — без якога-лібо айхоўвання і без участі аутэнтыфікацыі — яно з самага пачатку не было конфідэнцыйным. Це проста публічны ключ, які мае працаваць у браузеры. (Інодзе ён знаходзіцца ў окремым файле .js; якщо раздел «Паказаць код» нічога не прадстаўляе, спробуйце панель «Ўтвары коду» у інструментах разработчыка і абшукуйце за дапамогою Ctrl+Shift+F).
Адна хорашая практыка: перш чым працаваць над зворачным аналізам канца-тэпу, пераканайцеся, чы не праставляе компанія ўжо задокументаваны публічны чы сапраўднікавы API. Такія зазвычай ўсё бол стабільныя, чым тые, якія вы знайшлі, працюючы з інструментарамі разработчыка.
Шаг 6: Калі даны ўжо не надаюцца ад самага продавца
Інодзе запит, які вы шукаеце, нават не падае на домэн самага продавца — у замен ён вядзе на сервіс трэцьей стороны, такі як bazaarvoice.com або judge.me. Гэта ўскладненне, што продавец не выкорыстоўвае саёню інфраструктуру атрыбутаў; ён арендуе систему у постачальніка і проста вбудоввае яго віджет на сторанцы.
Этыя API віджэтаў, якімі керуе постачальнік, зазвычай захоўваюцца менш строго, чым галоўны сайт продавца, адтолькі якія ўзначаны для вбудоввання ў тыячы некаляжных інтерфейсоў, а не для спецыяльнага выкрытва і блакавання збірачаў данных.
Што ў гэтым артыкуле навмысна не паказвана
Якщо вы выполнилі всі пункты вышэй, а запытак, які вам трэба, яшчэ і дае код 403, порожній тэла або ўсё, што нагадвае пункт контроля безпекі, а не рэальныя даны, то гэта не баг у вашам коде. Это значыць, што сайт актыўна выявіў, што вы не ў звычайнай сесіі браузера. Гэта завданне настолькі значныя, што заслуговае на самастоятнюю дыскусію, і самэ гэта є тама, дзе продовжыцца наступны артыкул.
Глосарый
Вікнага карточка сеті — панель DevTools, якая фіксуе кожны запыт, які выдае сторанка, а таксама тое, што было адправлена і што вернулася.
XHR / Fetch — два механізмы, якія викорыстоўвае JavaScript для выканання запытак у фонавым режыме без повнага перзапуску сторанкі; вікнагу карточку сеті можна фільтрацыяваць, каб паказаць толькі іх.
REST API — это распаўсюджаны шаблон API, пры яком кожны ресурс мае свой сабэтны URL, напрыклад /products/123/price.
GraphQL — это стыль API, пабудаваны навакол аднаго канцэнтраба, пры яком тэла запиту точна паказвае, калікі данней запрашваюцца.
Persisted query — это спрыткалка GraphQL, пры якой цэлы текст запиту заменяецца на компактны хеш, які сервер вядома распазнае.
API key — это значэнне, прыкладзеная да запиту для яго ідентыфікаціі; дзеяныя з іх ёсць сапраўды прыватныя, але большасць — грамадскія, назначаныя для кліентаў, і можа быць видныя ў браузеры будзь-каго.
Copy as cURL — это апцыя ў DevTools, якая ператварае зафіксаваны запит у выконвальны камандны запыв, што стаўкаеся для перагляду яго точных заголовакоў і кукі.
Віджет трэцьяго сторонньага — галузь функцыянальнасці, такая як раздзел з атрыбутамі, яку сайт не стварае сам, а ўбудоввае з продукту іншай компаніі.