API GraphQL со Scrapy

Я пытаюсь получить данные от https://www.ouedkniss.com/boutiques/immobilier. Я обнаружил, что ouedkniss.com использует GraphQL API. Я пытался использовать этот API, но не смог получить данные, а также разбить на страницы. Показывает ошибку. AttributeError: 'list' object has no attribute 'get' Не знаю, пропущу я здесь что-то еще или нет. Вот что я пробовал до сих пор:

import scrapy
import json
from ..items import OuedknissItem
from scrapy.loader import ItemLoader

class StoresSpider(scrapy.Spider):
    name = 'stores'
    allowed_domains = ['www.ouedkniss.com']
  

    def start_requests(self):
        payload = json.dumps([
        {
        "operationName": "SearchStore",
        "query": "query Campaign($slug: String!) {\n  project(slug: $slug) {\n    id\n    isSharingProjectBudget\n    risks\n    story(assetWidth: 680)\n    currency\n    spreadsheet {\n      displayMode\n      public\n      url\n      data {\n        name\n        value\n        phase\n        rowNum\n        __typename\n      }\n      dataLastUpdatedAt\n      __typename\n    }\n    environmentalCommitments {\n      id\n      commitmentCategory\n      description\n      __typename\n    }\n    __typename\n  }\n}\n",
        "variables": {
            "q": "", "filter": {
            "categorySlug": "immobilier", 
            "count": 12, "page": 1},
            "categorySlug": "immobilier",
            "count": 12,
            "page": 1
        },
        
        }
        ])
        headers= {
            "Content-Type": "application/json",
            # "X-Requested-With": "XMLHttpRequest",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"
            }
        yield scrapy.Request(
            url='https://api.ouedkniss.com/graphql',
            method = "POST",
            headers=headers,
            body=payload,
            callback=self.parse
            )
        return super().start_requests()

    def parse(self, response):
        json_resp = json.loads(response.body)
        # print(json_resp)
        stores = json_resp.get('data')[0].get('stores').get('data')
        for store in stores:
            loader = ItemLoader(item=OuedknissItem())
            loader.add_value('name', store.get('name'))
            yield loader.load_item()

Похоже, ошибка в вашей функции parse, можете показать результаты print(json_resp)?

Michel Floyd 12.12.2022 18:41

@Michel Floyd Нет вывода из печати (json_resp)

Raisul Islam 12.12.2022 18:43
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
2
111
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ваши данные json полезной нагрузки не были правильно отформатированы, поэтому на выходе были ошибки валидатора. Теперь он работает нормально.

import scrapy
import json
#from ..items import OuedknissItem
from scrapy.loader import ItemLoader

class StoresSpider(scrapy.Spider):
    name = 'stores'
    allowed_domains = ['www.ouedkniss.com']
  

    def start_requests(self):
        payload = json.dumps({
   "operationName":"SearchStore",
   "variables":{
      "q":"",
      "filter":{
         "categorySlug":"immobilier",
         "count":12,
         "page":1
      }
   },
   "query":"query SearchStore($q: String, $filter: StoreSearchFilterInput!) {\n  stores: storeSearch(q: $q, filter: $filter) {\n    data {\n      id\n      name\n      slug\n      description\n      imageUrl\n      followerCount\n      announcementsCount\n      url\n      mainLocation {\n        location {\n          region {\n            name\n            __typename\n          }\n          city {\n            name\n            __typename\n          }\n          __typename\n        }\n        __typename\n      }\n      announcements(count: 6, page: 1) {\n        data {\n          id\n          defaultMedia(size: SMALL) {\n            mediaUrl\n            __typename\n          }\n          __typename\n        }\n        __typename\n      }\n      __typename\n    }\n    paginatorInfo {\n      lastPage\n      __typename\n    }\n    __typename\n  }\n}\n"
})
        headers= {
            "Content-Type": "application/json",
            # "X-Requested-With": "XMLHttpRequest",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"
            }
        yield scrapy.Request(
            url='https://api.ouedkniss.com/graphql',
            method = "POST",
            headers=headers,
            body=payload,
            callback=self.parse
            )
        return super().start_requests()

    def parse(self, response):
        json_resp = json.loads(response.body)
        #print(json_resp)
        
        stores = json_resp.get('data').get('stores').get('data')[0]
        print(stores)
        # loader = ItemLoader(item=OuedknissItem())
        # yield loader.load_item()

Выход:

{'id': '7088', 'name': 'Rachid Dounia', 'slug': 'rachid-dounia', 'description': 'agence immobiliere', 'imageUrl': 'https://cdn.ouedkniss.com/stores/7088/Logo.jpg', 'followerCount': 4, 'announcementsCount': 11, 'url': '', 'mainLocation': {'location': {'region': {'name': 'Algiers', '__typename': 'Region'}, 'city': {'name': 'Cheraga', '__typename': 'City'}, '__typename': 'Location'}, '__typename': 'StoreLocation'}, 'announcements': {'data': [{'id': '34036104', 'defaultMedia': None, '__typename': 'Announcement'}, {'id': '33491623', 'defaultMedia': {'mediaUrl': 'https://cdn9.ouedkniss.com/200/medias/announcements/images/pA6vV/4llx7bXtpjVv8196UOgs3ebpXai5HAYl7rs51MAD.jpg', '__typename': 'AnnouncementMedia'}, '__typename': 'Announcement'}, {'id': '33491551', 'defaultMedia': None, '__typename': 'Announcement'}, {'id': '27271413', 'defaultMedia': None, '__typename': 'Announcement'}, {'id': '33794330', 'defaultMedia': None, '__typename': 'Announcement'}, {'id': '32853052', 'defaultMedia': None, '__typename': 'Announcement'}], '__typename': 'AnnouncementPagination'}, '__typename': 'Store'}
2022-12-13 00:09:28 [scrapy.core.engine] INFO: Closing spider (finished)
2022-12-13 00:09:28 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 1319,
 'downloader/request_count': 1,
 'downloader/request_method_count/POST': 1,
 'downloader/response_bytes': 3260,
 'downloader/response_count': 1,
 'downloader/response_status_count/200': 1,

Обновление вместе с разбиением на страницы полезной нагрузки:

import scrapy
import json
#from ..items import OuedknissItem
from scrapy.loader import ItemLoader

class StoresSpider(scrapy.Spider):
    name = 'stores'
    allowed_domains = ['www.ouedkniss.com']
  

    def start_requests(self):
        payload = {
            "operationName":"SearchStore",
            "variables":{
                "q":"",
                "filter":{
                "categorySlug":"immobilier",
                "count":12,
                "page": 1
                }},
            "query":"query SearchStore($q: String, $filter: StoreSearchFilterInput!) {\n  stores: storeSearch(q: $q, filter: $filter) {\n    data {\n      id\n      name\n      slug\n      description\n      imageUrl\n      followerCount\n      announcementsCount\n      url\n      mainLocation {\n        location {\n          region {\n            name\n            __typename\n          }\n          city {\n            name\n            __typename\n          }\n          __typename\n        }\n        __typename\n      }\n      announcements(count: 6, page: 1) {\n        data {\n          id\n          defaultMedia(size: SMALL) {\n            mediaUrl\n            __typename\n          }\n          __typename\n        }\n        __typename\n      }\n      __typename\n    }\n    paginatorInfo {\n      lastPage\n      __typename\n    }\n    __typename\n  }\n}\n"
            }
        headers= {
            "Content-Type": "application/json",
            # "X-Requested-With": "XMLHttpRequest",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"
            }
       
        for payload['variables']['filter']['page'] in range(1,3):
            yield scrapy.Request(
                url='https://api.ouedkniss.com/graphql',
                method = "POST",
                headers=headers,
                body=json.dumps(payload),
                callback=self.parse
                )
       
    

    def parse(self, response):
        json_resp = json.loads(response.body)
        #print(json_resp)
        
        stores = json_resp['data']['stores']['data']
        for store in stores:
            yield {
                'id':store['id']
            }
       

Это решило мою проблему. Просто маленькая вещь, как я могу разбить это на страницы?

Raisul Islam 12.12.2022 19:55

Снова узнал что-то новое от вас, сэр.

Raisul Islam 13.12.2022 10:23

Похоже, вы не передаете в запрос необходимые переменные.

У вас есть:

query Campaign($slug: String!) {… result fields}

Этот запрос ожидает одну переменную slug.

Между тем ваши переменные:

"variables": {
  "q": "", 
  "filter": {
    "categorySlug": "immobilier", 
    "count": 12, "page": 1},
    "categorySlug": "immobilier",
    "count": 12,
    "page": 1
   },
}

(Кстати, у вас есть count и categorySlug дважды)

Пытаться:

query Campaign($q: String, $filter: StoreSearchFilterInput!) {… result fields}

Вероятно, вам следует проверить response.ok, чтобы убедиться, что ваш запрос выполнен успешно, прежде чем пытаться его проанализировать.

Другие вопросы по теме

Похожие вопросы