Python Help

Menu

Pular para o conteúdo
  • Inicial
  • Por que Python?
  • IDEs Python
  • Sobre

Arquivo mensal: outubro 2017

Padrão

Publicado por

Valdir Stumm Jr

Postado no

30 de outubro de 2017

Publicado em

scrapy, web scraping

comentários

2 Comentários

Como autenticar um spider Scrapy em um website

Obs.: ainda não conhece o Scrapy? Então leia este tutorial.

Vez por outra os sistemas que a gente usa não entregam as informações da forma que desejamos. Seja o sistema do seu cartão de crédito que não lhe dá uma visualização legal dos seus gastos, ou até mesmo seu app de táxi que não lhe deixa fazer uma análise mais aprofundada dos trajetos que você tem feito.

Ah se todos eles tivessem um botãozinho “exportar tudo em JSON”! 🙂

A realidade é dura e a maioria dos apps não nos dão essa opção. Uma alternativa nesses casos é raspar os dados que desejamos do site do tal app, e isso envolve fazer seu web spider se autenticar no sistema. Nesse post, vamos ver como fazer para que um spider Scrapy faça login em um sistema qualquer.

Como funciona a autenticação em um website?

Existem várias maneiras diferentes, mas em linhas gerais a autenticação em websites funciona assim:

  1. O usuário acessa URL que contém formulário de login. Exemplo: http://quotes.toscrape.com/login
  2. O usuário preenche campos do formulário com suas credenciais e clica no botão de login
  3. O navegador envia os dados preenchidos para o servidor, no corpo de uma requisição HTTP do tipo POST
  4. O servidor valida as credenciais do usuário e envia de volta uma resposta contendo uma página indicando que o usuário se autenticou com sucesso e, juntamente com ela, um cookie de sessão.

O cookie de sessão é uma informação que o browser irá armazenar localmente e irá enviar juntamente com as requisições subsequentes ao mesmo website, de forma que o último possa identificar quem é o usuário fazendo tais requisições.

Assim sendo, nosso spider deverá reproduzir os passos recém descritos para que consiga se autenticar em um website. Então vamos a ele!

Nosso spider

Vamos construir um spider que se autentique em http://quotes.toscrape.com e de lá extraia o link para a página no Goodreads de cada autor, informação que só é visível para usuários autenticados.

Dê uma olhada no esqueleto do nosso spider:

# -*- coding:utf-8 -*-
import scrapy

class LoginSpider(scrapy.Spider):
    name = 'login-spider'
    start_urls = ['http://quotes.toscrape.com/login']

    def parse(self, response):
        # depois a gente vai implementar aqui o preenchimento do formulário
        # contido em response e fazer a requisição de login
        self.log('visitei a página de login: {}'.format(response.url))

    def parse_author_links(self, response):
        # aqui a gente vai extrair os links para as páginas dos autores
        # ou seja, quando chegar aqui, o spider já estará autenticado
        pass

Quando rodarmos nosso spider, o Scrapy vai chamar automaticamente o método parse() assim que a resposta para a URL http://quotes.toscrape.com/login tiver sido baixada e a mensagem de log será impressa. Vá em frente e rode o spider acima só pra ver isso acontecendo:

$ scrapy runspider loginspider.py

Manipulando o formulário

O formulário de login do nosso site está representado assim:





<form action="/login" method="post" accept-charset="utf-8" >
    <input type="hidden" name="csrf_token" value="fHQgXTCzxs...aOkolIudtjV"/>
    <label for="username">Username</label>
    <input type="text" class="form-control" id="username" name="username" />
    <label for="username">Password</label>
    <input type="password" class="form-control" id="password" name="password" />
    <input type="submit" value="Login" class="btn btn-primary" />
</form>




Perceba que temos 4 inputs nesse formulário: username, password, o botão de login em si e um campo oculto chamado csrf_token. Não vou entrar em detalhes sobre proteção CSRF, mas o que você precisa saber é que a maioria dos sites por aí vai ter um campo desses no formulário de login deles e que você precisa enviar tal campo juntamente com a requisição de autenticação. Caso contrário, o servidor não irá validar sua requisição.

No Scrapy, requisições do tipo POST podem ser feitas com um tipo especial de Request chamado FormRequest. Nossa requisição de autenticação será:

req = scrapy.FormRequest(
    url='http://quotes.toscrape.com/login',
    formdata={
        'username': 'john.doe',
        'password': 'anything',
        'csrf_token': token,
    },
    callback=self.parse_author_links,
}

Alguns detalhes importantes:

  • O valor do campo csrf_token é gerado dinamicamente para cada requisição à página de login. Assim, teremos que extrair ele da página de login antes de fazer a requisição.
  • A URL passada ao objeto FormRequest deve ser aquela encontrada no atributo action do formulário de login.
  • As chaves do dicionário passado ao parâmetro formdata devem usar como nome o valor do atributo name do input correspondente no formulário.

Agora que a gente já sabe como fazer uma requisição do tipo POST, vamos ao spider:

# -*- coding:utf-8 -*-
import scrapy
from scrapy.exceptions import CloseSpider

class LoginSpider(scrapy.Spider):
    name = 'login-spider'
    start_urls = ['http://quotes.toscrape.com/login']

    def parse(self, response):
        self.log('visitei a página de login: {}'.format(response.url))
        token = response.css('input[name="csrf_token"]::attr(value)').extract_first()
        yield scrapy.FormRequest(
            url='http://quotes.toscrape.com/login',
            formdata={
                'username': 'john.doe',
                'password': 'anything',
                'csrf_token': token,
            },
            callback=self.parse_author_links,
        )

    def parse_author_links(self, response):
        has_logout_link = response.css('a[href="/logout"]').extract_first()
        if not has_logout_link:
            raise CloseSpider('falha de autenticação')
        self.log('acabei de fazer login')

        links = response.css('.quote a[href*="goodreads.com"]::attr(href)').extract()
        for link in links:
            yield {'link': link}

        next_page = response.css('li.next a::attr(href)').extract_first()
        if next_page:
            yield scrapy.Request(
                url=response.urljoin(next_page),
                callback=self.parse_author_links,
            )

Na linha 11 (método parse()), extraímos o token da página para enviar junto com a requisição de autenticação e, logo em seguida, o método parse() gera a requisição POST para a URL de login. Repare que registramos o método self.parse_author_links como o callback para manipular a página enviada como resposta pelo servidor.

No método parse_author_links, verificamos se o botão de logout apareceu na página (o que indica que estamos autenticados) e, caso não esteja, encerramos a execução do spider (linha 25).

Depois disso, basta extrair as URLs dos autores (linhas 28-30). Veja a versão completa do spider aqui.

E o cookie de sessão?

Ah, lembra que falei no começo do artigo que o navegador armazena um cookie de sessão e envia ele junto com as requisições subsequentes pro mesmo site? Pois é, o Scrapy faz a mesma coisa pra gente. Ou seja, não precisamos nos preocupar em manter a sessão. 🙂

Simplificando um pouco

É bem comum termos que submeter valores presentes em campos ocultos (hidden) juntamente com os dados que preenchemos no formulário. Para facilitar a nossa vida, o Scrapy fornece um método chamado FormRequest.from_response(), que carrega automaticamente os valores dos campos do formulário que possuem valores default. Nosso método parse() ficaria assim se utilizássemos o from_response():

def parse(self, response):
    self.log('visitei a página de login: {}'.format(response.url))
    yield scrapy.FormRequest.from_response(
        response,
        formdata={
            'username': 'john.doe',
            'password': 'anything',
        },
        callback=self.parse_author_links,
    )

Como você pode ver, não precisamos extrair e passar o csrf token, nem passar a URL do formulário. O from_response já faz isso pra gente. 🙂

Por fim

Agora você já pode fazer um spider para extrair aqueles dados que você precisa para o seu relatório. Mas, antes de fazer seu spider, verifique se ele não está violando os termos de serviço do seu banco, ou seja lá qual sistema que você estiver acessando. 🙂

Compartilhar:

  • Clique para compartilhar no X(abre em nova janela) 18+
  • Clique para compartilhar no Telegram(abre em nova janela) Telegram
  • Clique para compartilhar no Pocket(abre em nova janela) Pocket
  • Clique para enviar um link por e-mail para um amigo(abre em nova janela) E-mail
  • Clique para imprimir(abre em nova janela) Imprimir
Curtir Carregando...

Buscar

Últimos posts

  • Preservando a ordem de sequências ao remover duplicatas
  • Como autenticar um spider Scrapy em um website
  • Esquisitices (ou não) no arredondamento em Python 3
  • Gerando amostras aleatórias com Reservoir Sampling em Python
  • Web scraping em páginas baseadas em JavaScript com Scrapy
  • Usando comando with para evitar acoplamento temporal
  • Customizando o prompt do IPython 5+
  • O estranho caso do else em loops
  • Tente outra vez
  • Funções anônimas em Python

Top 10

  • Árvore Binária de Busca em Python
  • Supresas divertidas em Python - Easter Eggs
  • Ordenação de uma lista
  • Conjuntos em Python
  • Colorindo grafos -- ou, como escolher cores para um mapa automaticamente

Categorias

algoritmos banco de dados dicas rápidas documentação estruturas listas misc módulos oo Python3 scrapy shell strings Uncategorized web web scraping

Posts por autor

  • Avatar de Elias Dorneles Elias Dorneles
  • Avatar de Valdir Stumm Jr Valdir Stumm Jr

Arquivos

  • fevereiro 2018 (1)
  • outubro 2017 (1)
  • setembro 2017 (1)
  • junho 2017 (1)
  • outubro 2016 (2)
  • setembro 2016 (1)
  • abril 2016 (1)
  • agosto 2015 (1)
  • fevereiro 2015 (1)
  • janeiro 2015 (3)
  • setembro 2014 (1)
  • agosto 2014 (1)
  • julho 2014 (1)
  • junho 2014 (1)
  • maio 2014 (1)
  • abril 2014 (2)
  • fevereiro 2014 (1)
  • janeiro 2014 (1)
  • dezembro 2013 (2)
  • novembro 2013 (1)
  • outubro 2013 (3)
  • setembro 2013 (4)
  • agosto 2013 (1)
  • julho 2013 (2)
  • junho 2013 (5)
  • maio 2013 (2)
  • abril 2013 (4)
  • março 2013 (6)
  • fevereiro 2013 (1)
  • janeiro 2013 (2)
  • dezembro 2012 (1)
  • novembro 2012 (2)
  • outubro 2012 (1)
  • setembro 2012 (4)
  • agosto 2012 (2)
  • julho 2012 (4)
  • junho 2012 (7)
  • maio 2012 (5)
  • abril 2012 (1)
  • março 2012 (1)
  • fevereiro 2012 (1)
  • janeiro 2012 (1)
  • dezembro 2011 (2)
  • novembro 2011 (7)
  • outubro 2011 (3)
  • setembro 2011 (2)
  • agosto 2011 (5)
  • julho 2011 (1)
  • março 2011 (4)
  • fevereiro 2011 (3)
  • janeiro 2011 (2)

Licença

Creative Commons License

RSS

RSS Feed RSS - Posts

Crie um website ou blog gratuito no WordPress.com.
Privacidade e cookies: Esse site utiliza cookies. Ao continuar a usar este site, você concorda com seu uso.
Para saber mais, inclusive sobre como controlar os cookies, consulte aqui: Política de cookies
  • Assinar Assinado
    • Image Python Help
    • Junte-se a 229 outros assinantes
    • Já tem uma conta do WordPress.com? Faça login agora.
    • Image Python Help
    • Assinar Assinado
    • Registre-se
    • Fazer login
    • Denunciar este conteúdo
    • Visualizar site no Leitor
    • Gerenciar assinaturas
    • Esconder esta barra
%d
    Crie um site como este com o WordPress.com
    Comece agora
    Advertisement