Сбор коллекций фанатов Bandcamp через POST
Я пытался очистить фан-страницы Bandcamp, чтобы получить список альбомов, которые они купили, и у меня возникают проблемы с эффективностью этого. Я что-то написал с помощью Selenium, но он довольно медленный, поэтому я хотел бы изучить решение, которое, возможно, отправило бы запрос POST на сайт и проанализировало бы JSON оттуда.
Вот образец страницы коллекции: https://bandcamp.com/nhoward
Вот код Selenium:
def scrapeFanCollection(url):
browser = getBrowser()
setattr(threadLocal, 'browser', browser)
#Go to url
browser.get(url)
try:
#Click show more button
browser.find_element_by_class_name('show-more').click()
#Wait two seconds
time.sleep(2)
#Scroll to the bottom loading full collection
scroll(browser, 2)
except Exception:
pass
#Return full album collection
soup_a = BeautifulSoup(browser.page_source, 'lxml', parse_only=SoupStrainer('a', {"class": "item-link"}))
#Empty array
urls = []
# Looping through all the a elements in the page source
for item in soup_a.find_all('a', {"class": "item-link"}):
url = item.get('href')
if(url != None):
urls.append(url)
return urls
4 ответа
Доступ к API можно получить следующим образом:
$ curl -X POST -H "Content-Type: Application/JSON" -d \
'{"fan_id":82985,"older_than_token":"1586531374:1498564527:a::","count":10000}' \
https://bandcamp.com/api/fancollection/1/collection_items
Я не встречал сценария, когда
"older_than_token"
был устаревшим, поэтому проблема сводится к получению
"fan_id"
учитывая URL-адрес.
Эта информация находится в большом двоичном объекте в
id="pagedata"
элемент.
>>> import json
>>> import requests
>>> from bs4 import BeautifulSoup
>>> res = requests.get("https://www.bandcamp.com/ggorlen")
>>> soup = BeautifulSoup(res.text, "lxml")
>>> user = json.loads(soup.find(id="pagedata")["data-blob"])
>>> user["fan_data"]["fan_id"]
82985
Собираем все вместе (основываясь на этом ответе):
import json
import requests
from bs4 import BeautifulSoup
fan_page_url = "https://www.bandcamp.com/ggorlen"
collection_items_url = "https://bandcamp.com/api/fancollection/1/collection_items"
res = requests.get(fan_page_url)
soup = BeautifulSoup(res.text, "lxml")
user = json.loads(soup.find(id="pagedata")["data-blob"])
data = {
"fan_id": user["fan_data"]["fan_id"],
"older_than_token": user["wishlist_data"]["last_token"],
"count": 10000,
}
res = requests.post(collection_items_url, json=data)
collection = res.json()
for item in collection["items"][:10]:
print(item["album_title"], item["item_url"])
я использую
user["wishlist_data"]["last_token"]
который имеет тот же формат, что и
"older_than_token"
на всякий случай это имеет значение.
Чтобы получить всю коллекцию, я изменил предыдущий код с
"older_than_token": user["wishlist_data"]["last_token"]
к
user["collection_data"]["last_token"]
который содержал правильный токен
Есть несколько разных ответов наolder_than_token
значение, но они, похоже, зависят от метаданных конкретной учетной записи. В этой проблеме на GitHub я нашел подсказку , которая, как мне кажется, решает ее: токен, который должен работать для всех, — это"[current unix time]::a::"
например, в большинстве оболочек Mac и Linux вы можете получить текущее значение с помощью:
$ echo "$(date +%s)::a::"
1700323510::a::
Когда я это делаю, кажется, что все всегда начинается с начала библиотеки, и я могу получить все это одним пакетом.
К сожалению для вас, этот конкретный сайт Bandcamp, похоже, не выполняет никаких вызовов HTTP API для получения списка альбомов. Вы можете проверить это с помощью инструментов разработчика вашего браузера, на вкладке "Сеть" нажмите на фильтр XHR. Похоже, что единственный сделанный вызов - это получение сведений о вашей коллекции.