Как парсить несколько фотографий/видео в одном посте в инстаграме на python?

Хочу извлечь линки всех изображений с ссылки, но у меня возникла проблема с извлечением информации с тега script

Код вот:

import requests
import json
from bs4 import BeautifulSoup as BS
import re

# Ссылка на полную страницу
url = 'https://www.instagram.com/p/B5n2EXjF_1C/'

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like 
Gecko) Chrome/83.0.4103.116 Safari/537.36'}


r = requests.get(url, headers=headers, allow_redirects=True)

soup = BS(r.content, 'html.parser')
script = soup.find('script', attrs={'type':"text/javascript"}, text=re.compile('window._sharedData'))
data = json.loads(script.next)
image_url = data['display_url']

print(image_url)

Вот ошибка:

Traceback (most recent call last): File "C:/Users/Desktop/test/venv/Test.py", line 19, in data = json.loads(script.next) File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\json\__init__.py", line 357, in loads return _default_decoder.decode(s) File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\json\decoder.py", line 337, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\json\decoder.py", line 355, in raw_decode raise JSONDecodeError("Expecting value", s, err.value) from None json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Не сильно умею работать с типами js, но если есть у кого-то желание и время помочь,буду вам очень признателен!


Ответы (1 шт):

Автор решения: gil9red

Изменения:

  • Вместо script.next использовал script.text
  • Добавил в регулярку правила захвата куска js
  • Добавил извлечение куска js (search(...).group(1))

Попробуйте:

import datetime as DT
import json
import re
import sys
from bs4 import BeautifulSoup as BS
import requests

JS_SHARED_DATA_PATTERN = re.compile('window._sharedData = ({.+});')

# Ссылка на полную страницу
url = 'https://www.instagram.com/p/B5n2EXjF_1C/'

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'}


r = requests.get(url, headers=headers)

soup = BS(r.content, 'html.parser')
script = soup.find('script', attrs={'type':"text/javascript"}, text=JS_SHARED_DATA_PATTERN)
print(script)
# <script type="text/javascript">window._sharedData = {"config":{"csrf_tok ...

print(script.text)
# window._sharedData = {"config":{"csrf_token":"RtSXgxK6b0Lh4Ag3wSFRebLUfdJRA9qc","viewer":null, ...

# FIX: Если script имеет содержимое, а script.text возвращает пустую строку, то 
# в регулярку можно отдавать str(script), т.е.: JS_SHARED_DATA_PATTERN.search(str(script))
# В bs4 версии 4.7.1 проблемы не было, а в 4.9.1 уже есть
m = JS_SHARED_DATA_PATTERN.search(script.text)
if not m:
    print(f'Not found "window._sharedData = "!')
    sys.exit()

shared_data_text = m.group(1)
print(shared_data_text)
# {"config":{"csrf_token":"RtSXgxK6b0Lh4Ag3wSFRebLUfdJRA9qc","viewer":null,"viewerId":null},"country_code": ...

data = json.loads(shared_data_text)
print(data)
# {'config': {'csrf_token': 'RtSXgxK6b0Lh4Ag3wSFRebLUfdJRA9qc', 'viewer': None, 'viewerId': None}, 'country_code': ...

Я бы еще добавил дамп html, что не прошли проверку, это полезно для разбора ошибок, например:

import datetime as DT
...

m = JS_SHARED_DATA_PATTERN.search(script.text)
if not m:
    file_name_dump = str(DT.datetime.now()).replace(':', '') + '.html'
    with open(file_name_dump, 'wb') as f:
        f.write(rs.content)
    print(f'Not found "window._sharedData = ", see: {file_name_dump}!')
    sys.exit()

Без bs4:

import datetime as DT
import json
import re
import sys
import requests

JS_SHARED_DATA_PATTERN = re.compile('window._sharedData = ({.+});')

# Ссылка на полную страницу
url = 'https://www.instagram.com/p/B5n2EXjF_1C/'

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'}

r = requests.get(url, headers=headers)

m = JS_SHARED_DATA_PATTERN.search(r.text)
if not m:
    print(f'Not found "window._sharedData = "!')
    sys.exit()
print(shared_data_text)

data = json.loads(shared_data_text)
print(data)
→ Ссылка