
Nesse tutorial você vai aprender como Realizar um Web Scraping com Ruby através de um passo a passo simples usando a Gem Mechanize.
Web Scraping é o ato de extrair informações de um site automaticamente (através de um script), essa técnica pode ser usada por exemplo para criar um site que compara preços de produtos, realizar analises de marketing, encontrar possíveis clientes entre infinitas possibilidades.
Então bora aprender o/
O que vamos desenvolver?
Nesse tutorial nós vamos criar um Web Scraping com Ruby que vai logar em um site, baixar a lista de produtos de todas as páginas disponíveis e depois armazena-la em uma arquivo local.
Para isso nós vamos usar um site simples de exemplo, mas você pode usar as mesmas técnicas para baixar informações e interagir com qualquer site na Web.
Passo a Passo
Agora vamos começar o desenvolvimento do nosso Web Scraping de exemplo, lembrando que você pode adaptar esse exemplo para interagir com outros sites 🙂
Preparando o site de exemplo
Para começar, você deve clonar o site de exemplo que eu preparei, instalar as Gems dele, criar o banco de dados, e rodar os seeds para incluir os produtos.
-
Clone o projeto rodando:
1git clone git@github.com:OneBitCodeBlog/Web-Scraping-Target.git -
Entre na pasta:
1cd Web-Scraping-Target -
Instale as Gems:
1bundle -
Crie o banco de dados e insira os produtos nele:
1rails db:create db:migrate db:seed -
Suba o projeto rodando:
1rails s -
Interaja com o projeto no browser para ficar mais claro como será a navegação do Web Scraping.
Preparando a base do nosso Web Scraping com Ruby
Vamos iniciar o desenvolvimento do nosso pequeno Web Scraping criando um Gemfile, incluindo a gem Mechanize e realizando a primeira interação com o site alvo.
-
Em um outro console, rode:
1mkdir Web-Scraping-Client -
Entre na pasta rodando:
1cd Web-Scraping-Client -
Crie um Gemfile rodando:
1touch Gemfile -
Coloque no seu Gemfile:
123source 'https://rubygems.org'gem 'mechanize' -
Instale a gem rodando:
1bundle -
Crie o arquivo principal do projeto rodando:
1touch get_product_list.rb -
Para podermos usar a Gem mechanize, inclua nele:
1require 'mechanize' -
Crie um Agent (Objeto que usaremos para interagir com a página) incluindo no arquivo:
1agent = Mechanize.new -
Baixe as informações da página incluindo no arquivo:
1page = agent.get('http://localhost:3000') -
Para imprimirmos o resultado, inclua também:
1puts page -
Para rodar o script:
1ruby get_product_list.rb -
Pronto, o resultado deve ser algo como:
12345678910111213141516171819202122232425=> #<Mechanize::Page{url #<URI::HTTP http://localhost:3000/users/sign_in>}{meta_refresh}{title "WebscrapperTarget"}{iframes}{frames}{links#<Mechanize::Page::Link "Sign up" "/users/sign_up">#<Mechanize::Page::Link "Forgot your password?" "/users/password/new">}{forms#<Mechanize::Form{name nil}{method "POST"}{action "/users/sign_in"}{fields[hidden:0x2af4f07f3428 type: hidden name: utf8 value: ✓][hidden:0x2af4f07f2d84 type: hidden name: authenticity_token value: V0tAGv1/4UXF56Ore1WPFBNmun8Y+t08/yKlaSdq/R1nd9AErPSYvWkZcvWwll/neL4IQ51/vn3d/g+v+EIfGA==][field:0x2af4f07f2758 type: email name: user[email] value: ][field:0x2af4f07f2190 type: password name: user[password] value: ][hidden:0x2af4f07f7b40 type: hidden name: user[remember_me] value: 0]}{radiobuttons}{checkboxes[checkbox:0x2af4f07f75b4 type: checkbox name: user[remember_me] value: false]}{file_uploads}{buttons [submit:0x2af4f07f6f38 type: submit name: commit value: Log in]}>}>
Realizando o Login
Agora vamos aprender como realizar o Login através da gem mechanize, lembrando, você pode usar essa mesma técnica para submeter qualquer form de uma página.
-
Para selecionar o Form da página, inclua no seu arquivo:
1login_form = page.formObs: Caso exista mais de um form, você pode selecionar pelo name: google_form = page.form(‘f’)
-
Para preencher o campo de email e o campo de senha com os dados corretos coloque:
12login_form.field_with(name: 'user[email]').value = 'example@example.com'login_form.field_with(name: 'user[password]').value = '123456' -
Para submeter o form e pegar a página de resultado, coloque:
1product_list_page = agent.submit(login_form) -
Pronto, seu arquivo deve estar dessa forma:
123456789101112131415161718require 'mechanize'# Cria o agente que vai interagir com as paginasagent = Mechanize.new# Acessa a pagina de loginpage = agent.get('http://localhost:3000')puts page# Seleciona o form da paginalogin_form = page.form# Preenche com os dados de login e submete o formlogin_form.field_with(name: 'user[email]').value = 'example@example.com'login_form.field_with(name: 'user[password]').value = '123456'product_list_page = agent.submit(login_form)
Baixando as informações e exibindo na tela
Vamos agora baixar as informações dos produtos da primeira página e exibir da tela um por um, para isso vamos precisar pegar os elementos da tabela onde os produtos se encontram e depois pegar cada uma das colunas.
-
Na nossa página os produtos são renderizados da seguinte maneira:
123456789101112<tbody><tr><td>HD Gel Bridge</td><td>Lucell</td><td>ST Auto Gel Mount</td><td>48.0</td><td><a href="/products/11">Show</a></td><td><a href="/products/11/edit">Edit</a></td><td><a data-confirm="Are you sure?" rel="nofollow" data-method="delete" href="/products/11">Destroy</a></td></tr>...Outros produtos</tbody> -
Então para selecionarmos a tabela da nossa página, podemos procurar pela Tag HTML tbody, e para pegar cada um dos produtos podemos fazer um looping no resultado do tbody para pegar cada uma das Tags HTML tr, então coloque no seu arquivo:
123product_list_page.search('tbody tr').each do |p|end -
Agora para pegarmos o array de colunas, podemos selecionar a Tag HTML td, então dentro do looping inclua:
1f = p.search('td') -
Agora para exibirmos inclua a baixo da linha incluida anteriormente ainda dentro do looping:
123456line = "title: #{f[0].text}, "line += "brand: #{f[1].text}, "line += "description: #{f[2].text}, "line += "price: #{f[3].text}"puts line -
Seu arquivo deve ter ficado dessa forma:
123456789101112131415161718192021222324252627require 'mechanize'# Cria o agente que vai interagir com as paginasagent = Mechanize.new# Acessa a pagina de loginpage = agent.get('http://localhost:3000')# Seleciona o form da paginalogin_form = page.form# Preenche com os dados de login e submete o formlogin_form.field_with(name: 'user[email]').value = 'example@example.com'login_form.field_with(name: 'user[password]').value = '123456'product_list_page = agent.submit(login_form)# Pega todas as linhas de produtosproduct_list_page.search('tbody tr').each do |p|# Extrai as colunas dos produtos, organiza e escreve no arquivof = p.search('td')line = "title: #{f[0].text}, "line += "brand: #{f[1].text}, "line += "description: #{f[2].text}, "line += "price: #{f[3].text}"puts lineend -
Para executar, rode:
1ruby get_product_list.rb -
O resultado deve ter sido semelhante a este:
12345678910title: Digital Kit, brand: Phonefunc, description: Aftercell Audible Case, price: 40.0title: Electric Transmitter, brand: Conix, description: Pens GPS Air Tuner, price: 62.0title: Air Output Kit, brand: Briont, description: Pyck Side Electric Dummy Groove, price: 79.0title: Power Receiver, brand: Amcell, description: Pouphforge Input Kit, price: 65.0title: Video Transmitter, brand: Lubalt, description: Pophforge Direct Case, price: 12.0title: Gel Power Adapter, brand: Amcell, description: Cygpod Portable Power System, price: 15.0title: Power Filter, brand: Reunix, description: Traffefunc Output Performance System, price: 94.0title: HD Input Bridge, brand: Phientforge, description: Aquanix Side Amplifier, price: 77.0title: Disc Audible System, brand: Pananix, description: Aquabalt Remote GPS Kit, price: 95.0title: Air Digital Transmitter, brand: Sinebalt, description: Phieph GPS Performance Ferrule, price: 84.0
Navegando pelas páginas e extraindo os produtos
Nosso site de exemplo divide o resultado em várias páginas, então nós vamos navegar pelas páginas disponíveis pegando todos os produtos.
-
Para realizarmos essa navegação entre N páginas, nós vamos precisar incluir um looping em volta do looping que já tinhamos (que pega os elementos da Tag HTML tr). Nesse looping vamos observar se existe uma próxima página ou se já estamos na última, caso exista nele vamos “clicar” para mudar de página assim que extrairmos o resultado dela.
Então em volta de:
123product_list_page.search('tbody tr').each do |p|...endInclua:
12345loop doproduct_list_page.search('tbody tr').each do |p|...endend -
Agora para que o looping pare quando acabarem as páginas, inclua no final dele:
1break unless product_list_page.link_with(text: 'Next ›')Obs: Nós estamos olhando na página (que está dentro de product_list_page) se existe um link com o text ‘Next ›’ (que é o resposável por passar de página).
-
Para mudarmos de página quando existir uma próxima, coloque depois da linha anterior mas ainda dentro do looping:
1product_list_page = product_list_page.link_with(text: 'Next ›').clickObs: Estamos selecionando o link e clicando nele com o .click e depois colocando a nova página na mesma variável da anterior (atualizando a página)
-
Seu arquivo deve ter ficado assim:
1234567891011121314151617181920212223242526272829303132333435require 'mechanize'# Cria o agente que vai interagir com as paginasagent = Mechanize.new# Acessa a pagina de loginpage = agent.get('http://localhost:3000')# Seleciona o form da paginalogin_form = page.form# Preenche com os dados de login e submete o formlogin_form.field_with(name: 'user[email]').value = 'example@example.com'login_form.field_with(name: 'user[password]').value = '123456'product_list_page = agent.submit(login_form)loop do# Pega todas as linhas de produtosproduct_list_page.search('tbody tr').each do |p|# Extrai as colunas dos produtos, organiza e escreve no arquivof = p.search('td')line = "title: #{f[0].text}, "line += "brand: #{f[1].text}, "line += "description: #{f[2].text}, "line += "price: #{f[3].text}"puts lineend# Se nao tiverem mais paginas para serem extraidas ele para o loopingbreak unless product_list_page.link_with(text: 'Next ›')# Pula de paginaproduct_list_page = product_list_page.link_with(text: 'Next ›').clickend -
Para executar, rode:
1ruby get_product_list.rb -
Seu resultado deve ser algo semelhante:
123title: Digital Kit, brand: Phonefunc, description: Aftercell Audible Case, price: 40.0title: Electric Transmitter, brand: Conix, description: Pens GPS Air Tuner, price: 62.0title: Air Output Kit, brand: Briont, description: Pyck Side Electric Dummy Groove, price: 79.0 ...Mais 28 produtos
Escrevendo o resultado em um arquivo externo
Nossa missão principal já foi concluida, agora apenas para complementar vamos escrever o resultado do nosso scraping em um arquivo externo .txt
-
Antes dos loopings inclua:
12out_file = File.new('product_list.txt', 'w')out_file.puts 'Product List:'Obs: Estamos criando um novo arquivo e incluindo um título nele
-
Dentro do looping mais interno substitua:
1puts linePor:
1out_file.puts line -
Depois dos loopings inclua:
1out_file.close -
Seu arquivo completo deve ter ficado assim:
123456789101112131415161718192021222324252627282930313233343536373839404142require 'mechanize'# Cria o agente que vai interagir com as paginasagent = Mechanize.new# Acessa a pagina de loginpage = agent.get('http://localhost:3000')# Seleciona o form da paginalogin_form = page.form# Preenche com os dados de login e submete o formlogin_form.field_with(name: 'user[email]').value = 'example@example.com'login_form.field_with(name: 'user[password]').value = '123456'product_list_page = agent.submit(login_form)# Cria um novo arquivo para guardar a lista de produtosout_file = File.new('product_list.txt', 'w')out_file.puts 'Product List:'# Realiza o looping para pegar todas as paginas de produtosloop do# Pega todas as linhas de produtosproduct_list_page.search('tbody tr').each do |p|# Extrai as colunas dos produtos, organiza e escreve no arquivof = p.search('td')line = "title: #{f[0].text}, "line += "brand: #{f[1].text}, "line += "description: #{f[2].text}, "line += "price: #{f[3].text}"out_file.puts lineend# Se nao tiverem mais paginas para serem extraidas ele para o loopingbreak unless product_list_page.link_with(text: 'Next ›')# Pula de paginaproduct_list_page = product_list_page.link_with(text: 'Next ›').clickendout_file.close -
Para executar, rode:
1ruby get_product_list.rb -
Pronto, verifique na mesma pasta do seu arquivo se existe um arquivo chamado product_list.txt, dentro dele você vai encontrar a mesma lista que foi impressa anteriormente o/
Desafio de fixação
Para fixar o que foi aprendido nesse tutorial eu proponho que você realize o seguinte desafio:
“Crie um novo arquivo de scraping que: Realize o login, depois click em Edit no primeiro produto, preencha o form para atualizar o registro mudando o name do produto para ‘OneBitCode’ e depois submeta esse form garantindo que a atualização funcionou”
Conclusão
Nesse Tutorial você aprendeu do zero como interagir com sites (realizando login, baixando informações e navegando) através de um script Ruby usando a gem Mechanize.
Para saber mais sobre os comandos da Gem Mechanize acesse: http://docs.seattlerb.org/mechanize/GUIDE_rdoc.html
Não deixe de fazer o desafio proposto, para fixar bem um conhecimento é necessário utiliza-lo 🙂
Se você curtiu esse tutorial e quer ver mais conteúdos por aqui nos ajude compartilhando esse link com outros programadores e comunidades, isso faz a diferença de verdade.
Muito obrigado por estar com a gente,
Grande abraço o/
Leonardo Scorza

Não perca nenhum conteúdo
Receba nosso resumo semanal com os novos posts, cursos, talks e vagas o/
Primeira vez no OneBitCode? Curtiu esse conteúdo?
O OneBitCode tem muito mais para você!
O OneBitCode traz conteúdos de qualidade, e em português, sobre programação com foco em Ruby on Rails e também JavaScript.
Além disso, aqui sempre levamos à você conteúdos valiosos sobre a carreira de programação, dicas sobre currículos, portfólios, perfil profissional, soft skills, enfim, tudo o que você precisa saber para continuar evoluindo como Programador(a)!
Fique por dentro de todos os conteúdos o/
Nossas redes sociais:
📹 • https://youtube.com/Onebitcode [Live todas as terças-feiras às 19h)
💻 • https://linkedin.com/company/onebitcode
🙂 • https://facebook.com/onebitcode
📱 • https://instagram.com/one_bit_code
🐦 • https://twitter.com/onebitcode
Nossos cursos:
🥇 • Programador Full Stack Javascript em 8 Semanas
💎 • no fee dating sites
⚙ • free online dating sites in germany without payment
🐞 • Minicurso de Testes para Ruby on Rails com RSpec
Espero que curta nossos conteúdos e sempre que precisar de ajuda, fala com a gente!
Estamos aqui para você 🙂
Bem-vindo à família OneBitCode o/
Muito bom, Leo… Estava precisando conhecer essa gem…
Por favor, se me permite, traga nos próximos posts a leitura de PDF’s e Imagens… Seria igualmente enriquecedor!
Grande abraço e sucesso!
Show(comecei a utilizar essa palavra por sua causa) ! Estou acabando um outro curso aqui da plataforma, depois vou fazer esse!
Parabéns e muito grato Leo, suas publicações são TOP!
E aiiiii Jonatas, beleza?
Fico feliz que esteja gostando,
Grande abraço e obrigado por estar com a gente o/
Muito bom! Leo, ajudou muito a fazer um scripts PDF + Dados do Wikipedia
eu tentei uma vez e foi o processo inicial de criar um banco de dados e subir o projeto mais fechei sem querer e n abre mais