Modern Web Scraping com BeautifulSoup e Selenium

HTML é quase intuitivo. CSS é um grande avanço que separa claramente a estrutura de uma página de sua aparência. JavaScript adiciona algum entusiasmo. Essa é a teoria. O mundo real é um pouco diferente.

Neste tutorial, você aprenderá como o conteúdo que vê no navegador realmente é renderizado e como raspá-lo quando necessário. Em particular, você aprenderá como raspar comentários dinâmicos. Nossas ferramentas serão Python e pacotes incríveis como requests, BeautifulSoup e Selenium.

Quando você deve usar o Web Scraping?

A raspagem da Web é a prática de buscar automaticamente o conteúdo de páginas da Web projetadas para interação com usuários humanos, analisando-as e extraindo algumas informações (possivelmente links de navegação para outras páginas). Às vezes é necessário se não houver outra maneira de extrair as informações necessárias. Idealmente, o aplicativo fornece uma API dedicada para acessar seus dados programaticamente. Existem várias razões pelas quais a raspagem da web deve ser seu último recurso:

  1. É frágil (as páginas da web que você está copiando podem mudar com frequência).
  2. Pode ser proibido (alguns aplicativos da web têm políticas contra raspagem).
  3. Pode ser lento e expansivo (se você precisar buscar e percorrer muito barulho).

Compreendendo páginas da Web do mundo real

Vamos entender o que estamos enfrentando observando a saída de algum código de aplicativo da web comum. No artigo Introdução ao Vagrant,

Para extrair qualquer conteúdo desta página, primeiro precisamos encontrar os elementos HTML que contêm o conteúdo da página.

Ver fonte da página

Todos os navegadores desde o início dos tempos (década de 1990) suportam a capacidade de visualizar o HTML da página atual. Aqui está um trecho da fonte de visualização de Introdução ao Vagrant que começa com um grande pedaço de JavaScript minificado e feio não relacionado ao artigo em si. Aqui está um pequena parte dela:

Fonte da página

Aqui está um HTML real da página:

HTML da página

Raspagem Estática vs. Raspagem Dinâmica

A raspagem estática ignora o JavaScript. Ele busca páginas da web do servidor sem a ajuda de um navegador. Você obtém exatamente o que vê em “visualizar fonte da página” e, em seguida, corta e corta. Se o conteúdo que você procura estiver disponível, você não precisa ir mais longe. No entanto, se o conteúdo estiver em um src URL, você precisa de raspagem dinâmica.

A raspagem dinâmica usa um navegador real (ou um navegador sem cabeça) e permite que o JavaScript faça seu trabalho. Em seguida, ele consulta o DOM para extrair o conteúdo que está procurando. Às vezes, você precisa automatizar o navegador simulando um usuário para obter o conteúdo de que precisa.

Raspagem estática com solicitações e BeautifulSoup

Vamos ver como a raspagem estática funciona usando dois pacotes impressionantes do Python: solicitações para buscar páginas da Web e BeautifulSoup para analisar páginas HTML.

Instalando Requests e BeautifulSoup

Instale o pipenv primeiro e depois: pipenv install requests beautifulsoup4

Isso criará um ambiente virtual para você também. Se você estiver usando o código do gitlab, basta pipenv install.

Buscando páginas

Buscar uma página com solicitações é uma linha: r = requests.get(url)

O objeto de resposta tem muitos atributos. Os mais importantes são ok e content. Se a solicitação falhar, então r.ok será falso e r.content conterá o erro. O conteúdo é um fluxo de bytes. Geralmente é melhor decodificá-lo para utf-8 ao lidar com texto:

1
>>> r = requests.get('https://www.c2.com/no-such-page')
2
>>> r.ok
3
False
4
>>> print(r.content.decode('utf-8'))
5

6

7
</span>404 Not Found<span style="color: #bb0066;font-weight: bold">
8

9

Not Found

10
The requested URL /ggg was not found on this server.

11

12
13
Apache/2.0.52 (CentOS) Server at www.c2.com Port 80
14

15

Se estiver tudo bem então r.content conterá a página da Web solicitada (igual à origem da página de exibição).

Encontrando elementos com BeautifulSoup

o get_page() A função abaixo busca uma página da Web por URL, decodifica-a para UTF-8 e a analisa em um objeto BeautifulSoup usando o analisador HTML.

1
def get_page(url):
2
    r = requests.get(url)
3
    content = r.content.decode('utf-8')
4
    return BeautifulSoup(content, 'html.parser')

Assim que tivermos um objeto BeautifulSoup, podemos começar a extrair informações da página. BeautifulSoup fornece muitas funções de localização para localizar elementos dentro da página e detalhar elementos aninhados profundamente.

As páginas de autor do Envato Tuts+ contêm vários tutoriais. Aqui está minha página de autor. Em cada página, há até 12 tutoriais. Se você tiver mais de 12 tutoriais, poderá navegar para a próxima página. O HTML para cada artigo está incluído em um

marcação. A função a seguir localiza todos os elementos do artigo na página, detalha seus links e extrai o atributo href para obter a URL do tutorial:

1
def get_page_articles(page):
2
    elements = page.findAll('article')
3
    articles = [e.a.attrs['href'] for e in elements]
4
    return articles

O código a seguir pega todos os artigos da minha página e os imprime (sem o prefixo comum):

1
page = get_page('https://tutsplus.com/authors/gigi-sayfan')
2
articles = get_page_articles(page)
3
prefix = 'https://code.tutsplus.com/tutorials'
4
for a in articles:
5
    print(a[len(prefix):])
6
    
7
Output:
8
9
docker-from-the-ground-up-building-images--cms-28166
10
how-to-implement-your-own-data-structure-in-python--cms-28723
11
professional-error-handling-with-python--cms-25950
12
write-professional-unit-tests-in-python--cms-25835
13
how-to-write-package-and-distribute-a-library-in-python--cms-28693
14
serialization-and-deserialization-of-python-objects-part-1--cms-26183
15
understand-how-much-memory-your-python-objects-use--cms-25609
16
fetching-data-in-your-react-application--cms-30670
17
rest-vs-grpc-battle-of-the-apis--cms-30711
18
regular-expressions-with-go-part-2--cms-30406
19
regular-expressions-with-go-part-1--cms-30403
20
8-things-that-make-jest-the-best-react-testing-framework--cms-30534

Raspagem dinâmica com selênio

A raspagem estática foi boa o suficiente para obter a lista de artigos, mas se precisarmos automatizar o navegador e interagir com o DOM de forma interativa, uma das melhores ferramentas para o trabalho é Selênio.

O Selenium é voltado principalmente para testes automatizados de aplicativos da Web, mas é ótimo como uma ferramenta de automação de navegador de uso geral.

Instalando o Selenium

Digite este comando para instalar o Selenium: pipenv install selenium

Escolha seu driver da Web

O Selenium precisa de um driver da web (o navegador que ele automatiza). Para web scraping, geralmente não importa qual driver você escolhe. Eu prefiro o driver Chrome. Siga as instruções neste guia do Selenium.

Chrome vs. PhantomJS

Em alguns casos, você pode preferir usar um navegador headless, o que significa que nenhuma interface do usuário é exibida. Teoricamente, o PhantomJS é apenas outro driver da web. Mas, na prática, as pessoas relataram problemas de incompatibilidade em que o Selenium funciona corretamente com o Chrome ou o Firefox e às vezes falha com o PhantomJS. Prefiro remover essa variável da equação e usar um driver da web de navegador real.

Vamos fazer uma raspagem dinâmica e usar o Selenium para raspar os comentários de um plug-in Javascript codecanyon localizado ga-analytics#sendMarketClickEvent”>aqui. Aqui estão as importações necessárias.

1
from selenium import webdriver

O próximo passo é criar um webdriver instância e obtenha o URL de comentários.

1
driver = webdriver.Chrome()
2
driver.get('https://codecanyon.net/item/whatshelp-whatsapp-help-and-support-plugin-for-javascript/42202303/comments')

Depois de obter o URL, temos que encontrar o elemento onde os comentários estão localizados. Para fazer isso, clique com o botão direito do mouse na página da Web e clique em inspecionar, conforme mostrado abaixo.

Os comentários estão incluídos no commentList Eu iria. Clique com o botão direito do mouse no elemento e copie o XPath conforme mostrado abaixo.

Em seguida, use o selênio para extrair o conteúdo do elemento que contém os comentários.

1
driver = webdriver.Chrome()
2
driver.get('https://codecanyon.net/item/whatshelp-whatsapp-help-and-support-plugin-for-javascript/42202303/comments')
3
modules = driver.find_elements('xpath','//*[@id="content"]/div/div[1]/div[4]')
4
for comment in comments:
5
    print(comment.text)

Aqui está a saída:

1
sunsuk
2
20 days ago
3
How to integrate to CI scripts?
4
3 other replies
5
ThemeAtelier AUTHOR
6
20 days ago
7
Yes. You can add 5 staffs. We have proper documentation how can you add it in your website. Please follow the instruction. You have to call usual js and CSS files then just need to put actual markup in the footer of your site.
8
sunsuk
9
20 days ago
10
How to add wa number? Any admin dashboard ?
11
ThemeAtelier AUTHOR
12
20 days ago
13
No admin. It just a script. So everything is code. You just need to change demo values to your own value.
14
HTML knowledge is require for installing it.
15
Deezia12
16
29 days ago
17
Hi Author,
18
Does it work for a php website?
19
ThemeAtelier AUTHOR
20
24 days ago
21
Yes. As It will work in php websites.
22
gigantium
23
about 1 month ago
24
This is support for multiuser or for SAAS function?
25
ThemeAtelier AUTHOR
26
about 1 month ago
27
It’s not a SAAS product to use for multiple users. You can use this in your single website with for giving chat support to your customers with single and multi user agents.
28
gigantium
29
about 1 month ago
30
Thanks for your kind response. Can you provide a demo to access the admin dashboard?
31
ThemeAtelier AUTHOR
32
about 1 month ago

Existem alguns cenários em que o navegador precisa carregar algum conteúdo dinâmico; isso pode tornar o processo de raspagem um pouco mais complicado. Felizmente, o driver de selênio fornece wait() objetos que esperam por um determinado período de tempo antes de localizar o elemento programaticamente.

Para usar a funcionalidade de espera, primeiro você precisa das seguintes importações:

1
from selenium import webdriver
2
from selenium.webdriver.common.by import By
3
from selenium.webdriver.support.wait import WebDriverWait
4
from selenium.webdriver.support import expected_conditions as EC

Em seguida, obtenha o url e aplique o wait() objeto ao elemento.

1
driver = webdriver.Chrome()
2
url = 'http://www.c2.com/loading-page'
3
driver.get(url)
4
5
element = WebDriverWait(driver, 5).until(
6
    EC.presence_of_element_located((By.ID, "loaded_element"))
7
)

Conclusão

A raspagem da Web é uma prática útil quando as informações necessárias estão acessíveis por meio de um aplicativo da Web que não fornece uma API apropriada. É preciso algum trabalho não trivial para extrair dados de aplicativos da Web modernos, mas ferramentas maduras e bem projetadas, como solicitações, BeautifulSoup e Selenium, valem a pena.

Este post foi atualizado com contribuições de Esther Vaati. Esther é desenvolvedora de software e escritora da Envato Tuts+.

Deixe uma resposta