Skip to content

Esse projeto tem como intuito facilitar o entendimento dos processos de utilização do framework Scrapy em conjunto com um deploy feito na nuvem usando Scrapy Cloud.

Notifications You must be signed in to change notification settings

Lucas382/ScrapyTemplate

Repository files navigation

Descrição:

Esse projeto tem como intuito facilitar o entendimento dos processos de utilização
do framework Scrapy em conjunto com um deploy feito na nuvem usando Scrapy Cloud.

Creditos: video FreeCodeCamp

👣 Passo a passo:


Instalação e primeiro contato:

Instalação Scrapy
  • Criar um novo projeto com ambiente virtual
  • Abrir terminal e instalar o Scrapy com o comando “pip install Scrapy”
Criar um projeto de Spider
  • Terminal: “scrapy startproject nomedoprojetoscraper”
Criar uma Spider
  • Navegar até a pasta “spiders” do projeto Scrapy criado
  • Terminal: “scrapy genspider spidername site.to.scrape.com”
Instalar ipython para facilitar os testes
  • Terminal: “pip install ipython”
  • No arquivo scrapy.cfg adicionar “SHELL= ipython” em baixo de default
Usando o terminal Ipython
  • Terminal: “scrapy shell” para ativar o terminal ipython

  • No terminal Ipython (chamaremos de ITerminal): “fetch('https://books.toscrape.com/')”

  • ITerminal: “response” ← <200 https://books.toscrape.com/>

  • Selecionando um elemento Iterminal: “response.css('article.product_pod')”

  • Sair do ITerminal usando: “exit”

  • Tipos de seleção Ipython:

    • Salvar em uma variável: “books = response.css('article.product_pod')”
    • Verificar tamanho da lista da variável: “len(books)”
    • Obter um item da lista: “book = books[0]”
    • Obter o texto de um elemento “a” dentro de um elemento “h3”: “book.css('h3 a::text').get()”
    • Obter o texto de um elemento dentro de outro elemento pela Classe: “book.css('.product_price .price_color::text').get()”
    • Obter o conteúdo de um atributo de um elemento: “book.css('h3 a').attrib['href']” ou “response.css('.next a::attr(href)').get()”
Alterando uma Spider nomedaspider.py (”bookspider.py”)
  • Alterar o método parse que receberá a response igual ao ITerminal 1.1
Ativando e testando uma Spider pelo terminal
  • Navegar até a pasta do projeto Scrapy, nesse caso bookscraper
  • Terminal: “scrapy crawl bookspider” Nota: o item “'item_scraped_count': 20” referencia a quantidade de itens raspados.
Percorrendo próximas páginas
  • Encontrar o elemento responsável pelo link da próxima página, nesse caso, “response.css('.next a::attr(href)').get()”
  • Adicionar lógica para percorrer próximas páginas usando callback “yield response.follow(next_page_url, callback=self.parse)” 1.2

Intermediário:

Adicionando Coleta de páginas dentro da página principal
  • Adicionar coleta de cada url de uma página do livro
  • Adicionar método para coletar informações de uma página usando callback “yield response.follow(book_url, callback=self.parse_book_page)” 2
Exportar os dados manualmente para um arquivo
  • Terminal: “scrapy crawl bookspider -O bookdata.csv” para criar em formato csv
  • Terminal: “scrapy crawl bookspider -O bookdata.json” para criar em formato json
  • Terminal: “scrapy crawl bookspider -o bookdata.json” para adicionar em formato json
Criando e populando um scrapy Item
  • Criar uma classe para o item no arquivo items.py 3.
  • Popular a classe do livro 3.1
Rodando uma pipeline para pré-processar um item
  • Habilitar a spider no arquivo de configurações da spider “settings.py” descomentando o objeto ITEM_PIPELINES = {} Nota: Em “ITEM_PIPELINES = {"bookscraper.pipelines.BookscraperPipeline": 300, }” o número 300 representa a prioridade, onde, quanto menor o valor mais “cedo” a pipeline vai rodar.
  • Alterar o método process_item do item no arquivo “pipelines.py” 4.
Salvando em um banco de dados
  • Podemos adicionar no arquivo de configurações da spider “settings.py” um objeto FEEDS = {'booksdata.json': {'format': 'json'}} para definir um formato padrão de saída quando rodarmos o comando “scrapy crawl bookspider” que é equivalente ao comando “scrapy crawl bookspider -O cleandata.json”
  • Podemos também sobrescrever uma configuração do arquivo settings.py dentro do arquivo bookspider.py (arquivo referente à spider), basta adicionar “custom_settings = { 'FEEDS': { 'booksdata.json': {'format': 'json'}, 'overwrite': True }}” ao código
  • Baixar e instalar SQLITE.
  • Adicionar uma classe no arquivo pipelines.py para lidar com o banco 5.
  • Adicionar um item no objeto ITEM_PIPELINES no arquivo settings.py com: "bookscraper.pipelines.SaveToSQLitePipeline": 400,"
Evitando bloqueio de requisição de um site
  • Criar método para adicionar header ao request 6.
  • Adicionar variáveis que o método necessitar 6.1
  • Adicionar middleware ao arquivo settings.py 6.2
Adicionando proxy às requisições
  • Adicionar configuração de proxy ao arquivo settings.py 7.
  • Alternativa usando um serviço pago 7.1
  • Alternativa usando scrapeops proxy api 7.2
Rodando uma Spider na nuvem

Criando um projeto Scrapy Cloud 8


  • Criar uma conta em “https://app.zyte.com
  • Ir até a aba Scrapy Cloud
  • Criar um novo projeto clicando em “Start Project”
  • Em Scrapy Cloud, navegar no projeto criado
  • Ir na sessão “SPIDERS/Code & Deploys”
  • Clicar no botão “Deploy My code”

Dando deploy do seu projeto


  • No terminal do seu projeto instalar o “shub” com o comando “pip install shub”
  • Terminal: “shub login"
  • Fornecer a chave de API após “API key: SUA-CHAVE-API”
  • Executar Deploy com o comando “shub deploy PROJECT-ID”
  • Aguardar execução do deploy e verificar no Dashboard

Rodando o projeto


  • No menu de navegação do site do Scrapy Cloud, ir em “JOBS/Dashboard”
  • Clicar em “Run”
  • Selecionar a Spider que deseja rodar
  • Clicar em “Run”

Nota: Caso não seja importado automaticamente, adicionar ao arquivo “scrapinghub.yml” a linha de código “requirements_file: requirements.txt” para que seja mapeado o arquivo de requirements.txt do projeto. Ver tutorial



Mais detalhes:

Spider base criada a partir do comando “scrapy genspyder bookspider book.toscrape.com”
 import scrapy
 
 
 class BookspiderSpider(scrapy.Spider):
     name = "bookspider"
     allowed_domains = ["books.toscrape.com"]
     start_urls = ["https://books.toscrape.com"]
 
     def parse(self, response):
         pass

(Voltar ao topo)

1.1 Alterando o método parse para retornar um objeto com atributos vindos da response
  import scrapy
  
  
  class BookspiderSpider(scrapy.Spider):
      name = "bookspider"
      allowed_domains = ["books.toscrape.com"]
      start_urls = ["https://books.toscrape.com"]
  
      def parse(self, response):
          pass

(Voltar ao topo)

1.2 Adicionando coleta de páginas
import scrapy


class BookspiderSpider(scrapy.Spider):
    name = "bookspider"
    allowed_domains = ["books.toscrape.com"]
    start_urls = ["https://books.toscrape.com"]

    def parse(self, response):
        books = response.css('article.product_pod')

        for book in books:
            yield{
                'name': book.css('h3 a::text').get(),
                'price': book.css('div p.price_color::text').get(),
                'url': book.css('h3 a').attrib['href']
            }

		#------------------------------------------------------------------------------------------------
        next_page = response.css('.next a::attr(href)').get()

        if next_page is not None:
            if 'catalogue/' in next_page:
                next_page_url = 'https://books.toscrape.com/' + next_page
            else:
                next_page_url = 'https://books.toscrape.com/catalogue/' + next_page
            yield response.follow(next_page_url, callback=self.parse)

(Voltar ao topo)

2.Adicionando raspagem de cada página do livro
  import scrapy
  
  
  class BookspiderSpider(scrapy.Spider):
      name = "bookspider"
      allowed_domains = ["books.toscrape.com"]
      start_urls = ["https://books.toscrape.com"]
  
      def parse(self, response):
          books = response.css('article.product_pod')
  
  #---------------------------------------Alterado-------------------------------------------------
          for book in books:
              book_relative_url = book.css('h3 a::attr(href)').get()
              if 'catalogue/' in book_relative_url:
                  book_url = 'https://books.toscrape.com/' + book_relative_url
              else:
                  book_url = 'https://books.toscrape.com/catalogue/' + book_relative_url
              yield response.follow(book_url, callback=self.parse_book_page)
  #------------------------------------------------------------------------------------------------
  
          next_page = response.css('.next a::attr(href)').get()
          if next_page is not None:
              if 'catalogue/' in next_page:
                  next_page_url = 'https://books.toscrape.com/' + next_page
              else:
                  next_page_url = 'https://books.toscrape.com/catalogue/' + next_page
              yield response.follow(next_page_url, callback=self.parse)
  
  #----------------------------------------Adicionado----------------------------------------------
      def parse_book_page(self, response):
          table_rows = response.css("table tr")
          yield {
              'url': response.url,
              'title': response.css('.product_main h1::text').get(),
              'product_type': table_rows[1].css('td ::text').get(),
              'price_excl_tax': table_rows[2].css('td ::text').get(),
              'price_excl_tax': table_rows[2].css('td ::text').get(),
              'tax': table_rows[4].css('td ::text').get(),
              'availability': table_rows[5].css('td ::text').get(),
              'num_reviews': table_rows[6].css('td ::text').get(),
              'stars' : response.css('p.star-rating::attr(class)').get(),
              'category': response.xpath("//ul[@class='breadcrumb']/li[@class='active']/preceding-sibling::li[1]/a/text()").get(),
              'description': response.xpath("//div[@id='product_description']/following-sibling::p/text()").get(),
              'price': response.css('p.price_color::text').get()
          }
  
  """
  	Nota: Em category e description foi usado Xpath
  	no caso de category foi pego o elemento irmão (de mesmo nivel) anterior ao elemento li de classe 'active'
  	no caso da description foi pego o elemento irmão (de mesmo nivel) posterior ao elemento div de cladesse 'product_description'
  """

(Voltar ao topo)

3.Adicionando um item
    #items.py
    
    class BookItem(scrapy.Item):
        url = scrapy.Field()
        title = scrapy.Field()
        upc = scrapy.Field()
        product_type = scrapy.Field()
        price_excl_tax = scrapy.Field()
        price_incl_tax = scrapy.Field()
        tax = scrapy.Field()
        availability = scrapy.Field()
        num_reviews = scrapy.Field()
        stars = scrapy.Field()
        category = scrapy.Field()
        description = scrapy.Field()
        price = scrapy.Field()

Nota: “É possível serializar um campo ou vários campos criando uma função e passando ela como parametro serializer.”

    def serialize_price(value):
        return f'£ {str(value)}'
    
    
    class BookItem(scrapy.Item):
        url = scrapy.Field()
        title = scrapy.Field()
        upc = scrapy.Field()
        product_type = scrapy.Field()
        price_excl_tax = scrapy.Field()
        price_incl_tax = scrapy.Field()
        tax = scrapy.Field()
        availability = scrapy.Field()
        num_reviews = scrapy.Field()
        stars = scrapy.Field()
        category = scrapy.Field()
        description = scrapy.Field()
        price = scrapy.Field(serializer=serialize_price)

(Voltar ao topo)

3.1 Populando a classe
    #bookspider.py
    
    import scrapy
    
    from bookscraper.items import BookItem
    
    
    class BookspiderSpider(scrapy.Spider):
        name = "bookspider"
        allowed_domains = ["books.toscrape.com"]
        start_urls = ["https://books.toscrape.com"]
    
        def parse(self, response):
            books = response.css('article.product_pod')
    
            for book in books:
                book_relative_url = book.css('h3 a::attr(href)').get()
                if 'catalogue/' in book_relative_url:
                    book_url = 'https://books.toscrape.com/' + book_relative_url
                else:
                    book_url = 'https://books.toscrape.com/catalogue/' + book_relative_url
                yield response.follow(book_url, callback=self.parse_book_page)
    
            next_page = response.css('.next a::attr(href)').get()
            if next_page is not None:
                if 'catalogue/' in next_page:
                    next_page_url = 'https://books.toscrape.com/' + next_page
                else:
                    next_page_url = 'https://books.toscrape.com/catalogue/' + next_page
                yield response.follow(next_page_url, callback=self.parse)
    
    #----------------------------Alterado---------------------------------------------
        def parse_book_page(self, response):
            table_rows = response.css("table tr")
            book_item = BookItem()
    
            book_item['url'] = response.url,
            book_item['title'] = response.css('.product_main h1::text').get(),
            book_item['upc'] = table_rows[0].css('td ::text').get(),
            book_item['product_type'] = table_rows[1].css('td ::text').get(),
            book_item['price_excl_tax'] = table_rows[2].css('td ::text').get(),
            book_item['price_incl_tax'] = table_rows[3].css('td ::text').get(),
            book_item['tax'] = table_rows[4].css('td ::text').get(),
            book_item['availability'] = table_rows[5].css('td ::text').get(),
            book_item['num_reviews'] = table_rows[6].css('td ::text').get(),
            book_item['stars'] = response.css('p.star-rating::attr(class)').get(),
            book_item['category'] = response.xpath("//ul[@class='breadcrumb']/li[@class='active']/preceding-sibling::li[1]/a/text()").get(),
            book_item['description'] = response.xpath("//div[@id='product_description']/following-sibling::p/text()").get(),
            book_item['price'] = response.css('p.price_color::text').get()
    
            yield book_item

(Voltar ao topo)

4 Criando uma pipeline
    # Define your item pipelines here
    #
    # Don't forget to add your pipeline to the ITEM_PIPELINES setting
    # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
    
    
    # useful for handling different item types with a single interface
    from itemadapter import ItemAdapter
    
    
    class BookscraperPipeline:
    
        def process_item(self, item, spider):adapter = ItemAdapter(item)
    
            # Strip all whitespaces from strings
            field_names = adapter.field_names()
    
            for field_name in field_names:
                if field_name != 'description':
                    value = adapter.get(field_name)
                    if isinstance(adapter[field_name], tuple):
                        adapter[field_name] = value[0].strip()
                    else:
                        adapter[field_name] = value.strip()
                else:
                    value = adapter.get(field_name)
                    adapter[field_name] = str(value[0])
    
            # Category & Product Type --> switch to lowercase
            lowercase_keys = ['category', 'product_type']
            for lowercase_key in lowercase_keys:
                value = adapter.get(lowercase_key)
                adapter[lowercase_key] = value.lower()
    
            # Price --> convert to float
            price_keys = ['price_excl_tax', 'price_incl_tax', 'tax', 'price']
            for price_key in price_keys:
                value = adapter.get(price_key)
                value = value.replace('£', '')
                adapter[price_key] = float(value)
    
            # Availability --> extract number of books in stock (removing strings)
            availability_string = adapter.get('availability')
            split_string_array = availability_string.split('(')
            if len(split_string_array) < 2:
                adapter['availability'] = 0
            else:
                availability_string = split_string_array[1].split(' ')
                adapter['availability'] = int(availability_string[0])
    
            # Reviews --> convert string to int
            num_reviews_string = adapter.get('num_reviews')
            adapter['num_reviews'] = int(num_reviews_string)
    
            # Stars --> covert text to number
            stars_string = adapter.get('stars')
            split_stars_array = stars_string.split(' ')
            stars_text_value = split_stars_array[1].lower()
            if stars_text_value == "zero":
                adapter['stars'] = 0
            elif stars_text_value == "one":
                adapter['stars'] = 1
            elif stars_text_value == "two":
                adapter['stars'] = 2
            elif stars_text_value == "three":
                adapter['stars'] = 3
            elif stars_text_value == "four":
                adapter['stars'] = 4
            elif stars_text_value == "five":
                adapter['stars'] = 5
    
            return item

(Voltar ao topo)

5 Classe para lidar com o banco

Nota: Os metodos open_spider, close_spider e process_item serão encontrados pelo scrapy e são executados automaticamente no devido tempo de vida da spider.

    #pipelines.py
    
    class SaveToSQLitePipeline:
    
        def open_spider(self, spider):
            self.conn = sqlite3.connect('books.db')
            self.cur = self.conn.cursor()
            self.cur.execute("""
            CREATE TABLE IF NOT EXISTS books (
                id INTEGER PRIMARY KEY,
                url TEXT,
                title TEXT,
                upc TEXT,
                product_type TEXT,
                price_excl_tax REAL,
                price_incl_tax REAL,
                tax REAL,
                availability INTEGER,
                num_reviews INTEGER,
                stars REAL,
                category TEXT,
                description TEXT,
                price REAL
            );
            """)
    
        def close_spider(self, spider):
            self.conn.close()
    
        def process_item(self, item, spider):
            query = """
                INSERT INTO books (
                    url, title, upc, product_type, price_excl_tax, price_incl_tax,
                    tax, availability, num_reviews, stars, category, description, price
                )
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """
    
            values = (
                item['url'],
                item['title'],
                item['upc'],
                item['product_type'],
                item['price_excl_tax'],
                item['price_incl_tax'],
                item['tax'],
                item['availability'],
                item['num_reviews'],
                item['stars'],
                item['category'],
                item['description'],
                item['price']
            )
    
            self.cur.execute(query, values)
            self.conn.commit()
            return item

(Voltar ao topo)

6 Criando cabeçalhos (headers)
    #middlewares.py
    
    class ScrapeOpsFakeBrowserHeaderAgentMiddleware:
    
        @classmethod
        def from_crawler(cls, crawler):
            return cls(crawler.settings)
    
        def __init__(self, settings):
            self.scrapeops_api_key = settings.get('SCRAPEOPS_API_KEY')
            self.scrapeops_endpoint = settings.get('SCRAPEOPS_FAKE_BROWSER_HEADER_ENDPOINT')
            self.scrapeops_fake_browser_headers_active = settings.get('SCRAPEOPS_FAKE_BROWSER_HEADER_ENABLED')
            self.scrapeops_num_results = settings.get('SCRAPEOPS_NUM_RESULTS')
            self.headers_list = []
            self._get_headers_list()
            self._scrapeops_fake_browser_headers_enabled()
    
        def _get_headers_list(self):
            payload = {'api_key': self.scrapeops_api_key}
            if self.scrapeops_num_results is not None:
                payload['num_results'] = self.scrapeops_num_results
            response = requests.get(self.scrapeops_endpoint, params=urlencode(payload))
            json_response = response.json()
            self.headers_list = json_response.get('result', [])
    
        def _get_random_browser_header(self):
            random_index = randint(0, len(self.headers_list) - 1)
            return self.headers_list[random_index]
    
        def _scrapeops_fake_browser_headers_enabled(self):
            if self.scrapeops_api_key is None or self.scrapeops_api_key == '' or self.scrapeops_fake_browser_headers_active == False:
                self.scrapeops_fake_browser_headers_active = False
            else:
                self.scrapeops_fake_browser_headers_active = True
    
        def process_request(self, request, spider):
            random_browser_header = self._get_random_browser_header()
            request.headers['user-agent'] = random_browser_header['user-agent']
            request.headers['accept'] = random_browser_header['accept']
            request.headers['sec-ch-ua'] = random_browser_header['sec-ch-ua']
            request.headers['sec-ch-ua-mobile'] = random_browser_header['sec-ch-ua-mobile']
            request.headers['sec-ch-ua-platform'] = random_browser_header['sec-ch-ua-platform']
            request.headers['sec-fetch-site'] = random_browser_header['sec-fetch-site']
            request.headers['sec-fetch-mod'] = random_browser_header['sec-fetch-mod']
            request.headers['sec-fetch-user'] = random_browser_header['sec-fetch-user']
            request.headers['accept-encoding'] = random_browser_header['accept-encoding']
            request.headers['accept-language'] = random_browser_header['accept-language']
    
            print(random_browser_header)

(Voltar ao topo)

6.1 Adicionando variáveis
    #settings.py
    
    SCRAPEOPS_API_KEY = 'a889d691-4e9a-4c25-a26b-a7faec67ebfe' #api-key-just-for-exampl;e
    
    # SCRAPEOPS_FAKE_USER_AGENT_ENDPOINT = 'https://headers.scrapeops.io/v1/user-agents'
    SCRAPEOPS_FAKE_BROWSER_HEADER_ENDPOINT = 'https://headers.scrapeops.io/v1/browser-headers'
    
    # SCRAPEOPS_FAKE_USER_AGENT_ENABLED = True
    SCRAPEOPS_FAKE_BROWSER_HEADER_ENABLED = True
    
    SCRAPEOPS_NUM_RESULTS = 50

(Voltar ao topo)

6.2 Adicionar a classe ao middlewares
    #settings.py
    
    DOWNLOADER_MIDDLEWARES = {
       # "bookscraper_project.middlewares.BookscraperDownloaderMiddleware": 543,
       # 'bookscraper.middlewares.ScrapeOpsFakeUserAgentMiddleware': 400,
       'bookscraper.middlewares.ScrapeOpsFakeBrowserHeaderAgentMiddleware': 400,
    }

(Voltar ao topo)

7 Configurações de proxy

Terminal: “pip install scrapy-rotating-proxies”

Adicionar variáveis de ambiente

    #settings.py
    
    ROTATING_PROXY_LIST = [
       '45.70.204.233:4145',
       '45.7.177.224:39867',
       '187.73.55.66:5678',
    ]
    
    DOWNLOADER_MIDDLEWARES = {
       # "bookscraper_project.middlewares.BookscraperDownloaderMiddleware": 543,
       # 'bookscraper.middlewares.ScrapeOpsFakeUserAgentMiddleware': 400,
       'bookscraper.middlewares.ScrapeOpsFakeBrowserHeaderAgentMiddleware': 400,
       'rotating_proxies.middlewares.RotatingProxyMiddleware': 610,
       'rotating_proxies.middlewares.BanDetectionMiddleware': 620,
    }

(Voltar ao topo)

7.1 Alternativa usando serviço pago smart proxy

Site: https://dashboard.smartproxy.com

Tutorial: freeCode

Depois de comprar um plano seguir os passos:

Criar um usuario

create_user

Adicionar configurações

add_configs

Obter o endpoint

get_endpoints

Criar uma classe para o proxy

create_class_proxy create_class_proxy_2

Adicionar variáveis de ambiente

add_env_vars

Adicionar middleware

add_middleware

(Voltar ao topo)

7.2 Usando scrapeops proxy api

Terminal: “pip install scrapeops-scrapy-proxy-sdk”

Adicionar variável de ambiente

    # settings.py
    
    SCRAPEOPS_API_KEY = 'YOUR_API_KEY'
    SCRAPEOPS_PROXY_ENABLED = True
    SCRAPEOPS_PROXY_SETTINGS = {'country': 'us'}
    
    DOWNLOADER_MIDDLEWARES = {
        'scrapeops_scrapy_proxy_sdk.scrapeops_scrapy_proxy_sdk.ScrapeOpsScrapyProxySdk': 725,
    }

Adicionar middleware para gerenciar as urls.

    ## middlewares.py
    
    from urllib.parse import urlencode
    from scrapy import Request
    
    class ScrapeOpsProxyMiddleware:
    
        @classmethod
        def from_crawler(cls, crawler):
            return cls(crawler.settings)
    
        def __init__(self, settings):
            self.scrapeops_api_key = settings.get('SCRAPEOPS_API_KEY')
            self.scrapeops_endpoint = 'https://proxy.scrapeops.io/v1/?'
            self.scrapeops_proxy_active = settings.get('SCRAPEOPS_PROXY_ENABLED', False)
    				self.scrapeops_proxy_settings = {}
            self._clean_proxy_settings(settings.get('SCRAPEOPS_PROXY_SETTINGS'))
    
        @staticmethod
        def _replace_response_url(response):
            real_url = response.headers.get(
                'Sops-Final-Url', def_val=response.url)
            return response.replace(
                url=real_url.decode(response.headers.encoding))
        
        def _clean_proxy_settings(self, proxy_settings):
            if proxy_settings is not None:
                for key, value in proxy_settings.items():
                    clean_key = key.replace('sops_', '')
                    self.scrapeops_proxy_settings[clean_key] = value
        
        def _get_scrapeops_url(self, request):
            payload = {'api_key': self.scrapeops_api_key, 'url': request.url}
            
            ## Global Request Settings
            if self.scrapeops_proxy_settings is not None:
                for key, value in self.scrapeops_proxy_settings.items():
                    payload[key] = value
    
            ## Request Level Settings 
            for key, value in request.meta.items():
                if 'sops_' in key:
                    clean_key = key.replace('sops_', '')
                    payload[clean_key] = value
    
            proxy_url = self.scrapeops_endpoint + urlencode(payload)
            return proxy_url
    
        def _scrapeops_proxy_enabled(self):
            if self.scrapeops_api_key is None or self.scrapeops_api_key == '' or self.scrapeops_proxy_active == False:
                return False
            return True
        
        def process_request(self, request, spider):
            if self._scrapeops_proxy_enabled is False or self.scrapeops_endpoint in request.url:
                return None
            
            scrapeops_url = self._get_scrapeops_url(request)
            new_request = request.replace(
                cls=Request, url=scrapeops_url, meta=request.meta)
            return new_request
    
        def process_response(self, request, response, spider):
            new_response = self._replace_response_url(response)
            return new_response

Resultado: result

(Voltar ao topo)

8 Rodando projeto na nuvem usando Scrapy Cloud

Criar uma conta em “https://app.zyte.com/account/login/?next=/o/599648/scrapycloud/discover”

1

no menu lateral navegar até scrapy Cloud

2

Clicar em start project

3

Dar um nome ao projeto

6

Navegar a pagina de Code & Deploy 1.0

7

Navegar a pagina de Code & Deploy 1.1

8

Instalar shub no projeto (O projeto atual foi criado no Pycharm então foi usado o próprio console do Pycharm)

9

Logar no shub 1.0: digitar comando de login

10

Logar no shub 1.1: Inserir chave API

11

11 1

Executar Deploy do projeto para o shub

12

Aguardar o Deplyoy

13

Sucesso!

14

Inserir o nome da Spider e Clicar em Run

15

Navegar até o Dashboard do projeto e clicar em Run

16

Virificar conclusão na seção “Completed”

17

Acompanhar execução na seção “Running”

18

No caso atual ocorreram 4 erros, para investigar melhor clicaremos no numero logo abaixo da coluna “Errors”na tabela da seção “Completed”.

19

Podemos investigar os erros na seguinte página, podendo expandir cada erro para ver o log do erro em específico.

20

O erro é decorrido da falta do módulo “itemadapter” que utilizamos em uma classe dentro do arquivo pupelines.py para indicar um livro como um item

21

O erro em questão está ocorrendo pois no deploy do projeto não estamos indicando os requisitos que o projeto está utilizando. para isso criaremos um arquivo requirements.txt na raiz do nosso projeto e adicionaremos a versão do itemadapter que estamos utilizando

22

Em seguida no arquivo scrapinghub.yml adicionaremos a linha de código “requirements_file: requirements.txt” logo a baixo do id do projeto para indicar o caminho do nosso arquivo requirements.

23

Executaremos novamente o Deploy do projeto

24

No site de gerenciamento de deploy iremos navegar até a seção de deploy para verificar o andamento do nosso deploy

25

Aguardaremos o progesso do deploy. Note que temos um numero 2 que indica que esse é o segundo deploy desse projeto.

26

Indicação de sucesso do deploy.

27

Podemos clicar na seção que acabamos de implantar(Deploy) e navegar até a aba “Requirements” para verificar que nosso requirements.txt foi implementado com sucesso!

28

Seguiremos os passos de execução da spider e se tudo correr bem teremos uma execução em andamento da nossa spyder. caso contrario investigue os erros para resolver o problema.

29

Agora no Dashboard podemos ver que a spyder rodou com sucesso e tambem podemos ver a que falhou.

30

Clicando no numero do item podemos verificar os itens coletados.

31

Nessa parte também é possível baixar todos os itens em um formato desejado dentre os disponiveis.

32

(Voltar ao topo)

About

Esse projeto tem como intuito facilitar o entendimento dos processos de utilização do framework Scrapy em conjunto com um deploy feito na nuvem usando Scrapy Cloud.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages