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()