Python Web Scraping - Websites dinâmicos

Neste capítulo, vamos aprender como realizar web scraping em sites dinâmicos e os conceitos envolvidos em detalhes.

Introdução

Web scraping é uma tarefa complexa e a complexidade se multiplica se o site for dinâmico. De acordo com a Auditoria Global de Acessibilidade da Web das Nações Unidas, mais de 70% dos sites são de natureza dinâmica e contam com JavaScript para suas funcionalidades.

Exemplo de site dinâmico

Vejamos um exemplo de um site dinâmico e saibamos por que é difícil de raspar. Aqui, vamos dar um exemplo de pesquisa em um site chamadohttp://example.webscraping.com/places/default/search.Mas como podemos dizer que este site é de natureza dinâmica? Pode ser julgado pela saída do seguinte script Python, que tentará extrair dados da página da web mencionada acima -

import re
import urllib.request
response = urllib.request.urlopen('http://example.webscraping.com/places/default/search')
html = response.read()
text = html.decode()
re.findall('(.*?)',text)

Resultado

[ ]

A saída acima mostra que o raspador de exemplo falhou ao extrair informações porque o elemento <div> que estamos tentando encontrar está vazio.

Abordagens para coleta de dados de sites dinâmicos

Vimos que o raspador não pode extrair as informações de um site dinâmico porque os dados são carregados dinamicamente com JavaScript. Nesses casos, podemos usar as duas técnicas a seguir para extrair dados de sites dinâmicos dependentes de JavaScript -

  • JavaScript de engenharia reversa
  • Renderizando JavaScript

JavaScript de engenharia reversa

O processo chamado engenharia reversa seria útil e nos permite entender como os dados são carregados dinamicamente por páginas da web.

Para fazer isso, precisamos clicar no inspect elementguia para um URL especificado. A seguir, vamos clicarNETWORK guia para encontrar todas as solicitações feitas para essa página da web, incluindo search.json com um caminho de /ajax. Em vez de acessar os dados AJAX do navegador ou via guia NETWORK, também podemos fazer isso com a ajuda do seguinte script Python -

import requests
url=requests.get('http://example.webscraping.com/ajax/search.json?page=0&page_size=10&search_term=a')
url.json()

Exemplo

O script acima nos permite acessar a resposta JSON usando o método Python json. Da mesma forma, podemos baixar a resposta da string bruta e, usando o método json.loads do python, podemos carregá-la também. Estamos fazendo isso com a ajuda do seguinte script Python. Basicamente, ele raspará todos os países pesquisando a letra do alfabeto 'a' e, em seguida, iterando as páginas resultantes das respostas JSON.

import requests
import string
PAGE_SIZE = 15
url = 'http://example.webscraping.com/ajax/' + 'search.json?page={}&page_size={}&search_term=a'
countries = set()
for letter in string.ascii_lowercase:
   print('Searching with %s' % letter)
   page = 0
   while True:
   response = requests.get(url.format(page, PAGE_SIZE, letter))
   data = response.json()
   print('adding %d records from the page %d' %(len(data.get('records')),page))
   for record in data.get('records'):countries.add(record['country'])
   page += 1
   if page >= data['num_pages']:
      break
   with open('countries.txt', 'w') as countries_file:
   countries_file.write('n'.join(sorted(countries)))

Depois de executar o script acima, obteremos a seguinte saída e os registros serão salvos no arquivo chamado countries.txt.

Resultado

Searching with a
adding 15 records from the page 0
adding 15 records from the page 1
...

Renderizando JavaScript

Na seção anterior, fizemos engenharia reversa na página da web que explicava como a API funcionava e como podemos usá-la para recuperar os resultados em uma única solicitação. No entanto, podemos enfrentar as seguintes dificuldades ao fazer engenharia reversa -

  • Às vezes, os sites podem ser muito difíceis. Por exemplo, se o site for feito com uma ferramenta de navegador avançada, como o Google Web Toolkit (GWT), o código JS resultante será gerado por máquina e difícil de entender e fazer engenharia reversa.

  • Alguns frameworks de nível superior, como React.js pode dificultar a engenharia reversa, abstraindo a lógica JavaScript já complexa.

A solução para as dificuldades acima é usar um mecanismo de renderização do navegador que analisa HTML, aplica a formatação CSS e executa JavaScript para exibir uma página da web.

Exemplo

Neste exemplo, para renderizar o Java Script, usaremos um módulo Python familiar Selenium. O seguinte código Python irá renderizar uma página da web com a ajuda do Selenium -

Primeiro, precisamos importar o webdriver do selênio da seguinte forma -

from selenium import webdriver

Agora, forneça o caminho do driver da web que baixamos de acordo com nossos requisitos -

path = r'C:\\Users\\gaurav\\Desktop\\Chromedriver'
driver = webdriver.Chrome(executable_path = path)

Agora, forneça a url que queremos abrir naquele navegador da web agora controlado por nosso script Python.

driver.get('http://example.webscraping.com/search')

Agora, podemos usar o ID da caixa de ferramentas de pesquisa para definir o elemento a ser selecionado.

driver.find_element_by_id('search_term').send_keys('.')

Em seguida, podemos usar java script para definir o conteúdo da caixa de seleção da seguinte maneira -

js = "document.getElementById('page_size').options[1].text = '100';"
driver.execute_script(js)

A linha de código a seguir mostra que a pesquisa está pronta para ser clicada na página da web -

driver.find_element_by_id('search').click()

A próxima linha de código mostra que ele aguardará 45 segundos para concluir a solicitação AJAX.

driver.implicitly_wait(45)

Agora, para selecionar links de países, podemos usar o seletor CSS da seguinte maneira -

links = driver.find_elements_by_css_selector('#results a')

Agora o texto de cada link pode ser extraído para a criação da lista de países -

countries = [link.text for link in links]
print(countries)
driver.close()