Introducción a Web Scraping

En este notebook veremos algunos ejemplos sencillos de web scraping y al mismo tiempo aprenderemos un poco de HTML. La razón por la cual veremos HTML es porque al scrapear es útil identificar la estructura general de una página web y saber donde es posible que se encuentre la información que buscamos. El saber un poco de HTML nos facilitará el extraer la información.

Pero ¿Qué es Web Scraping?

En palabras llanas es una técnica que se apoya en el uso de la programación para extraer información de páginas web y tratar de estructurarla de tal forma que sea útil para trabajar con ella.

¿Y qué es HTML?

HTML son las siglas de HyperText Markup Language y es el lenguaje estándar en que se hacen las páginas de internet. Prácticamente todo las páginas que vemos en internet son en su mayoría cientos e incluso miles de líneas de este lenguaje.

En HTML todo está encerrado por lo que se conoce como etiquetas que se pueden entender como instrucciones para los navegadores que les indican la forma y estilo del texto encerrado entre éstas. La estructura general de una página escrita en HTML es la siguiente:

......... . . .

.....

. . .

.....

. . .

Todo lo que está entre <> son las etiquetas. Como podemos ver todas tienen una pareja <..></...>, <...> indica el inicio de una etiqueta y </...> el final de ésta. Las principales etiquetas son estas:

<title>Indica el título de la página (el que vemos en la pestaña del navegador)</title>

<body>En esta etiqueta se encuentra todo el contenido de la página</body>

<h1,h2,h3...h6>Indican los títulos que hay dentro del texto</h1...>

<p>Indican parrafos</p>

<a ...>Indican links</a>

<td ...>Indican texto dentro de una tabla</td>

<strong>Indica texto en negritas</strong>

<img ...>Indica una imagen</img>

Algunas etiquetas incluyen lo que se conoce como clases y atributos que modifican las características de la etiqueta. Son fácil identificarlos ya que se escriben después de la etiqueta y siempre llevan un signo = .

Para estos ejemplos introductorios usaremos una página relativamene sencilla de scrapear. Empezaremos cargando la página que utilizaremos en este notebook.

from IPython.display import HTML HTML('')

Con el código anterior cargamos la página de la cual extraeremos la información.

Primer Ejemplo

Para este primer ejemplo lo que haremos es obtener el título de la página web (el que aparece en la pestaña del navegador). Es importante recalcar que antes de cualquier cosa debemos importar las librerías que necesitaremos.


In [21]:
import urllib.request
import bs4
import re

Con las instrucciones anteriores hemos cargado las librería que usaremos para el scrapping. Urllib.request nos permite acceder a las páginas, Beautiful Soup (bs4) nos permite parsear la página, re es la librería de Python de expresiones regulares.

Para aprender más acerca del uso de estas librerías podemos vistar las siguientes páginas: Beautiful Soup

urllib.request

re

Después de que importamos la librerías podemos empezar a trabajar con la página. Lo primero que debemos hacer con una página es abrirla, para eso crearemos una función para facilitar la tarea.


In [22]:
def createSoup(url):
	pageUrl = urllib.request.urlopen(url)
	pageHtml = pageUrl.read()
	pageUrl.close()
	return bs4.BeautifulSoup(pageHtml)

Con la función anterior abriremos la página, después la leeremos crearemos la sopa y cerraremos la página.

A continuación le indicaremos al programa con que página debe hacer todo lo anterior.


In [23]:
soup = createSoup("file:///C:/users/victo_~1/appdata/local/temp/30.html")

Con la instrucción anterior hemos guardado todo el archivo HTML en la variable soup. Para comprobarlo veamos que tiene soup al imprimir esta variable.


In [24]:
print(soup)


<!DOCTYPE html>
<html><head><meta charset="utf-8"/><style>body {
  width: 45em;
  border: 1px solid #ddd;
  outline: 1300px solid #fff;
  margin: 16px auto;
}

body .markdown-body
{
  padding: 30px;
}

@font-face {
  font-family: octicons-anchor;
  src: url(data:font/woff;charset=utf-8;base64,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) format('woff');
}

.markdown-body {
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  color: #333;
  overflow: hidden;
  font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  word-wrap: break-word;
}

.markdown-body a {
  background: transparent;
}

.markdown-body a:active,
.markdown-body a:hover {
  outline: 0;
}

.markdown-body strong {
  font-weight: bold;
}

.markdown-body h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

.markdown-body img {
  border: 0;
}

.markdown-body hr {
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  height: 0;
}

.markdown-body pre {
  overflow: auto;
}

.markdown-body code,
.markdown-body kbd,
.markdown-body pre {
  font-family: monospace, monospace;
  font-size: 1em;
}

.markdown-body input {
  color: inherit;
  font: inherit;
  margin: 0;
}

.markdown-body html input[disabled] {
  cursor: default;
}

.markdown-body input {
  line-height: normal;
}

.markdown-body input[type="checkbox"] {
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  padding: 0;
}

.markdown-body table {
  border-collapse: collapse;
  border-spacing: 0;
}

.markdown-body td,
.markdown-body th {
  padding: 0;
}

.markdown-body * {
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.markdown-body input {
  font: 13px/1.4 Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
}

.markdown-body a {
  color: #4183c4;
  text-decoration: none;
}

.markdown-body a:hover,
.markdown-body a:focus,
.markdown-body a:active {
  text-decoration: underline;
}

.markdown-body hr {
  height: 0;
  margin: 15px 0;
  overflow: hidden;
  background: transparent;
  border: 0;
  border-bottom: 1px solid #ddd;
}

.markdown-body hr:before {
  display: table;
  content: "";
}

.markdown-body hr:after {
  display: table;
  clear: both;
  content: "";
}

.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
  margin-top: 15px;
  margin-bottom: 15px;
  line-height: 1.1;
}

.markdown-body h1 {
  font-size: 30px;
}

.markdown-body h2 {
  font-size: 21px;
}

.markdown-body h3 {
  font-size: 16px;
}

.markdown-body h4 {
  font-size: 14px;
}

.markdown-body h5 {
  font-size: 12px;
}

.markdown-body h6 {
  font-size: 11px;
}

.markdown-body blockquote {
  margin: 0;
}

.markdown-body ul,
.markdown-body ol {
  padding: 0;
  margin-top: 0;
  margin-bottom: 0;
}

.markdown-body ol ol,
.markdown-body ul ol {
  list-style-type: lower-roman;
}

.markdown-body ul ul ol,
.markdown-body ul ol ol,
.markdown-body ol ul ol,
.markdown-body ol ol ol {
  list-style-type: lower-alpha;
}

.markdown-body dd {
  margin-left: 0;
}

.markdown-body code {
  font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
}

.markdown-body pre {
  margin-top: 0;
  margin-bottom: 0;
  font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
}

.markdown-body .octicon {
  font: normal normal 16px octicons-anchor;
  line-height: 1;
  display: inline-block;
  text-decoration: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

.markdown-body .octicon-link:before {
  content: '\f05c';
}

.markdown-body>*:first-child {
  margin-top: 0 !important;
}

.markdown-body>*:last-child {
  margin-bottom: 0 !important;
}

.markdown-body .anchor {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  display: block;
  padding-right: 6px;
  padding-left: 30px;
  margin-left: -30px;
}

.markdown-body .anchor:focus {
  outline: none;
}

.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
  position: relative;
  margin-top: 1em;
  margin-bottom: 16px;
  font-weight: bold;
  line-height: 1.4;
}

.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
  display: none;
  color: #000;
  vertical-align: middle;
}

.markdown-body h1:hover .anchor,
.markdown-body h2:hover .anchor,
.markdown-body h3:hover .anchor,
.markdown-body h4:hover .anchor,
.markdown-body h5:hover .anchor,
.markdown-body h6:hover .anchor {
  padding-left: 8px;
  margin-left: -30px;
  line-height: 1;
  text-decoration: none;
}

.markdown-body h1:hover .anchor .octicon-link,
.markdown-body h2:hover .anchor .octicon-link,
.markdown-body h3:hover .anchor .octicon-link,
.markdown-body h4:hover .anchor .octicon-link,
.markdown-body h5:hover .anchor .octicon-link,
.markdown-body h6:hover .anchor .octicon-link {
  display: inline-block;
}

.markdown-body h1 {
  padding-bottom: 0.3em;
  font-size: 2.25em;
  line-height: 1.2;
  border-bottom: 1px solid #eee;
}

.markdown-body h2 {
  padding-bottom: 0.3em;
  font-size: 1.75em;
  line-height: 1.225;
  border-bottom: 1px solid #eee;
}

.markdown-body h3 {
  font-size: 1.5em;
  line-height: 1.43;
}

.markdown-body h4 {
  font-size: 1.25em;
}

.markdown-body h5 {
  font-size: 1em;
}

.markdown-body h6 {
  font-size: 1em;
  color: #777;
}

.markdown-body p,
.markdown-body blockquote,
.markdown-body ul,
.markdown-body ol,
.markdown-body dl,
.markdown-body table,
.markdown-body pre {
  margin-top: 0;
  margin-bottom: 16px;
}

.markdown-body hr {
  height: 4px;
  padding: 0;
  margin: 16px 0;
  background-color: #e7e7e7;
  border: 0 none;
}

.markdown-body ul,
.markdown-body ol {
  padding-left: 2em;
}

.markdown-body ul ul,
.markdown-body ul ol,
.markdown-body ol ol,
.markdown-body ol ul {
  margin-top: 0;
  margin-bottom: 0;
}

.markdown-body li>p {
  margin-top: 16px;
}

.markdown-body dl {
  padding: 0;
}

.markdown-body dl dt {
  padding: 0;
  margin-top: 16px;
  font-size: 1em;
  font-style: italic;
  font-weight: bold;
}

.markdown-body dl dd {
  padding: 0 16px;
  margin-bottom: 16px;
}

.markdown-body blockquote {
  padding: 0 15px;
  color: #777;
  border-left: 4px solid #ddd;
}

.markdown-body blockquote>:first-child {
  margin-top: 0;
}

.markdown-body blockquote>:last-child {
  margin-bottom: 0;
}

.markdown-body table {
  display: block;
  width: 100%;
  overflow: auto;
  word-break: normal;
  word-break: keep-all;
}

.markdown-body table th {
  font-weight: bold;
}

.markdown-body table th,
.markdown-body table td {
  padding: 6px 13px;
  border: 1px solid #ddd;
}

.markdown-body table tr {
  background-color: #fff;
  border-top: 1px solid #ccc;
}

.markdown-body table tr:nth-child(2n) {
  background-color: #f8f8f8;
}

.markdown-body img {
  max-width: 100%;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.markdown-body code {
  padding: 0;
  padding-top: 0.2em;
  padding-bottom: 0.2em;
  margin: 0;
  font-size: 85%;
  background-color: rgba(0,0,0,0.04);
  border-radius: 3px;
}

.markdown-body code:before,
.markdown-body code:after {
  letter-spacing: -0.2em;
  content: "\00a0";
}

.markdown-body pre>code {
  padding: 0;
  margin: 0;
  font-size: 100%;
  word-break: normal;
  white-space: pre;
  background: transparent;
  border: 0;
}

.markdown-body .highlight {
  margin-bottom: 16px;
}

.markdown-body .highlight pre,
.markdown-body pre {
  padding: 16px;
  overflow: auto;
  font-size: 85%;
  line-height: 1.45;
  background-color: #f7f7f7;
  border-radius: 3px;
}

.markdown-body .highlight pre {
  margin-bottom: 0;
  word-break: normal;
}

.markdown-body pre {
  word-wrap: normal;
}

.markdown-body pre code {
  display: inline;
  max-width: initial;
  padding: 0;
  margin: 0;
  overflow: initial;
  line-height: inherit;
  word-wrap: normal;
  background-color: transparent;
  border: 0;
}

.markdown-body pre code:before,
.markdown-body pre code:after {
  content: normal;
}

.markdown-body .highlight {
  background: #fff;
}

.markdown-body .highlight .h {
  color: #333;
  font-style: normal;
  font-weight: normal;
}

.markdown-body .highlight .mf,
.markdown-body .highlight .mh,
.markdown-body .highlight .mi,
.markdown-body .highlight .mo,
.markdown-body .highlight .il,
.markdown-body .highlight .m {
  color: #945277;
}

.markdown-body .highlight .s,
.markdown-body .highlight .sb,
.markdown-body .highlight .sc,
.markdown-body .highlight .sd,
.markdown-body .highlight .s2,
.markdown-body .highlight .se,
.markdown-body .highlight .sh,
.markdown-body .highlight .si,
.markdown-body .highlight .sx,
.markdown-body .highlight .s1 {
  color: #df5000;
}

.markdown-body .highlight .kc,
.markdown-body .highlight .kd,
.markdown-body .highlight .kn,
.markdown-body .highlight .kp,
.markdown-body .highlight .kr,
.markdown-body .highlight .kt,
.markdown-body .highlight .k,
.markdown-body .highlight .o {
  font-weight: bold;
}

.markdown-body .highlight .kt {
  color: #458;
}

.markdown-body .highlight .c,
.markdown-body .highlight .cm,
.markdown-body .highlight .c1 {
  color: #998;
  font-style: italic;
}

.markdown-body .highlight .cp,
.markdown-body .highlight .cs,
.markdown-body .highlight .cp .h {
  color: #999;
  font-weight: bold;
}

.markdown-body .highlight .cs {
  font-style: italic;
}

.markdown-body .highlight .n {
  color: #333;
}

.markdown-body .highlight .na,
.markdown-body .highlight .nv,
.markdown-body .highlight .vc,
.markdown-body .highlight .vg,
.markdown-body .highlight .vi {
  color: #008080;
}

.markdown-body .highlight .nb {
  color: #0086B3;
}

.markdown-body .highlight .nc {
  color: #458;
  font-weight: bold;
}

.markdown-body .highlight .no {
  color: #094e99;
}

.markdown-body .highlight .ni {
  color: #800080;
}

.markdown-body .highlight .ne {
  color: #990000;
  font-weight: bold;
}

.markdown-body .highlight .nf {
  color: #945277;
  font-weight: bold;
}

.markdown-body .highlight .nn {
  color: #555;
}

.markdown-body .highlight .nt {
  color: #000080;
}

.markdown-body .highlight .err {
  color: #a61717;
  background-color: #e3d2d2;
}

.markdown-body .highlight .gd {
  color: #000;
  background-color: #fdd;
}

.markdown-body .highlight .gd .x {
  color: #000;
  background-color: #faa;
}

.markdown-body .highlight .ge {
  font-style: italic;
}

.markdown-body .highlight .gr {
  color: #aa0000;
}

.markdown-body .highlight .gh {
  color: #999;
}

.markdown-body .highlight .gi {
  color: #000;
  background-color: #dfd;
}

.markdown-body .highlight .gi .x {
  color: #000;
  background-color: #afa;
}

.markdown-body .highlight .go {
  color: #888;
}

.markdown-body .highlight .gp {
  color: #555;
}

.markdown-body .highlight .gs {
  font-weight: bold;
}

.markdown-body .highlight .gu {
  color: #800080;
  font-weight: bold;
}

.markdown-body .highlight .gt {
  color: #aa0000;
}

.markdown-body .highlight .ow {
  font-weight: bold;
}

.markdown-body .highlight .w {
  color: #bbb;
}

.markdown-body .highlight .sr {
  color: #017936;
}

.markdown-body .highlight .ss {
  color: #8b467f;
}

.markdown-body .highlight .bp {
  color: #999;
}

.markdown-body .highlight .gc {
  color: #999;
  background-color: #EAF2F5;
}

.markdown-body kbd {
  background-color: #e7e7e7;
  background-image: -webkit-linear-gradient(#fefefe, #e7e7e7);
  background-image: linear-gradient(#fefefe, #e7e7e7);
  background-repeat: repeat-x;
  display: inline-block;
  padding: 3px 5px;
  font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
  line-height: 10px;
  color: #000;
  border: 1px solid #cfcfcf;
  border-radius: 2px;
}

.markdown-body .highlight .pl-coc,
.markdown-body .highlight .pl-entm,
.markdown-body .highlight .pl-eoa,
.markdown-body .highlight .pl-mai .pl-sf,
.markdown-body .highlight .pl-pdv,
.markdown-body .highlight .pl-sc,
.markdown-body .highlight .pl-sr,
.markdown-body .highlight .pl-v,
.markdown-body .highlight .pl-vpf {
  color: #0086b3;
}

.markdown-body .highlight .pl-eoac,
.markdown-body .highlight .pl-mdht,
.markdown-body .highlight .pl-mi1,
.markdown-body .highlight .pl-mri,
.markdown-body .highlight .pl-va,
.markdown-body .highlight .pl-vpu {
  color: #008080;
}

.markdown-body .highlight .pl-c,
.markdown-body .highlight .pl-pdc {
  color: #b4b7b4;
  font-style: italic;
}

.markdown-body .highlight .pl-k,
.markdown-body .highlight .pl-ko,
.markdown-body .highlight .pl-kolp,
.markdown-body .highlight .pl-mc,
.markdown-body .highlight .pl-mr,
.markdown-body .highlight .pl-ms,
.markdown-body .highlight .pl-s,
.markdown-body .highlight .pl-sok,
.markdown-body .highlight .pl-st {
  color: #6e5494;
}

.markdown-body .highlight .pl-ef,
.markdown-body .highlight .pl-enf,
.markdown-body .highlight .pl-enm,
.markdown-body .highlight .pl-entc,
.markdown-body .highlight .pl-eoi,
.markdown-body .highlight .pl-sf,
.markdown-body .highlight .pl-smc {
  color: #d12089;
}

.markdown-body .highlight .pl-ens,
.markdown-body .highlight .pl-eoai,
.markdown-body .highlight .pl-kos,
.markdown-body .highlight .pl-mh .pl-pdh,
.markdown-body .highlight .pl-mp,
.markdown-body .highlight .pl-pde,
.markdown-body .highlight .pl-stp {
  color: #458;
}

.markdown-body .highlight .pl-enti {
  color: #d12089;
  font-weight: bold;
}

.markdown-body .highlight .pl-cce,
.markdown-body .highlight .pl-enc,
.markdown-body .highlight .pl-kou,
.markdown-body .highlight .pl-mq {
  color: #f93;
}

.markdown-body .highlight .pl-mp1 .pl-sf {
  color: #458;
  font-weight: bold;
}

.markdown-body .highlight .pl-cos,
.markdown-body .highlight .pl-ent,
.markdown-body .highlight .pl-md,
.markdown-body .highlight .pl-mdhf,
.markdown-body .highlight .pl-ml,
.markdown-body .highlight .pl-pdc1,
.markdown-body .highlight .pl-pds,
.markdown-body .highlight .pl-s1,
.markdown-body .highlight .pl-scp,
.markdown-body .highlight .pl-sol {
  color: #df5000;
}

.markdown-body .highlight .pl-c1,
.markdown-body .highlight .pl-cn,
.markdown-body .highlight .pl-pse,
.markdown-body .highlight .pl-pse .pl-s2,
.markdown-body .highlight .pl-vi {
  color: #a31515;
}

.markdown-body .highlight .pl-mb,
.markdown-body .highlight .pl-pdb {
  color: #df5000;
  font-weight: bold;
}

.markdown-body .highlight .pl-mi,
.markdown-body .highlight .pl-pdi {
  color: #6e5494;
  font-style: italic;
}

.markdown-body .highlight .pl-ms1 {
  background-color: #f5f5f5;
}

.markdown-body .highlight .pl-mdh,
.markdown-body .highlight .pl-mdi {
  font-weight: bold;
}

.markdown-body .highlight .pl-mdr {
  color: #0086b3;
  font-weight: bold;
}

.markdown-body .highlight .pl-s2 {
  color: #333;
}

.markdown-body .highlight .pl-ii {
  background-color: #df5000;
  color: #fff;
}

.markdown-body .highlight .pl-ib {
  background-color: #f93;
}

.markdown-body .highlight .pl-id {
  background-color: #a31515;
  color: #fff;
}

.markdown-body .highlight .pl-iu {
  background-color: #b4b7b4;
}

.markdown-body .highlight .pl-mo {
  color: #969896;
}

.markdown-body .task-list-item {
  list-style-type: none;
}

.markdown-body .task-list-item+.task-list-item {
  margin-top: 3px;
}

.markdown-body .task-list-item input {
  float: left;
  margin: 0.3em 0 0.25em -1.6em;
  vertical-align: middle;
}</style><title>Día de muertos</title></head><body><article class="markdown-body"><h1>
<a aria-hidden="true" class="anchor" href="#d%C3%ADa-de-muertos" id="user-content-día-de-muertos"><span class="octicon octicon-link"></span></a>Día de muertos</h1>
<p><a href="https://camo.githubusercontent.com/542dc43836a693c022132fbb103942c7fce4d1e1/687474703a2f2f7777772e7265706f7274616a65732e6f72672f77702d636f6e74656e742f75706c6f6164732f323031302f31312f64254333254144612d64652d6d756572746f732e6a7067" target="_blank"><img alt="alt text" data-canonical-src="http://www.reportajes.org/wp-content/uploads/2010/11/d%C3%ADa-de-muertos.jpg" src="https://camo.githubusercontent.com/542dc43836a693c022132fbb103942c7fce4d1e1/687474703a2f2f7777772e7265706f7274616a65732e6f72672f77702d636f6e74656e742f75706c6f6164732f323031302f31312f64254333254144612d64652d6d756572746f732e6a7067" style="max-width:100%;"/></a></p>
<p>Una de las tradiciones más representativas del pueblo mexicano es el Día de Muertos. Los origenes de esta celebración se remontan varios siglos atrás , antes de la época de la Colonia. Civilizaciones como los <strong>olmecas</strong> , <strong>mayas</strong> y <strong>aztecas</strong> compartían algo en común, la creencia de una <strong>vida</strong> después de la muerte.</p>
<p>Para nuestros antepasados la <strong>muerte</strong> era sólo una parte de un <strong>ciclo</strong> de la vida. Al morir la persona emprendía un viaje al Mictlán, el mundo de los muertos, lugar de su eterno reposo.</p>
<p>Al llegar los españoles a México, las creencias prehispánicas se fusionaron con la religión católica dando como resultado lo que hoy conocemos como el Día de Muertos y que se celebra cada <strong>2</strong> de <strong>Noviembre</strong>.</p>
<h3>
<a aria-hidden="true" class="anchor" href="#elementos-escenciales-de-un-altar-de-muertos" id="user-content-elementos-escenciales-de-un-altar-de-muertos"><span class="octicon octicon-link"></span></a><em>Elementos escenciales de un altar de muertos</em>
</h3>
<table>
<thead>
<tr>
<th align="center">Elemento</th>
<th>Significado</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">Flor de Cempasúchil</td>
<td>Quiere decir flor de más de 20 pétalos en la lengua náhuatl. Sus pétalos se usan para marcar en el suelo el camino que deben seguir las almas de los difuntos.</td>
</tr>
<tr>
<td align="center">Velas</td>
<td>Se usan para orientar a las almas e iluminar su camino</td>
</tr>
<tr>
<td align="center">Sal</td>
<td>Símbolo de purificación</td>
</tr>
<tr>
<td align="center">Copal</td>
<td>Atrae las almas de los difuntos hacia el altar</td>
</tr>
<tr>
<td align="center">Comida</td>
<td>Se ponen los platillos favoritos del difunto a quien se ofrece el altar</td>
</tr>
<tr>
<td align="center">Agua</td>
<td>Se coloca un vaso con agua para calmar la sed del difunto después de su largo viaje</td>
</tr>
<tr>
<td align="center">Arco de flores</td>
<td>Simboliza la entrada al mundo de los muertos</td>
</tr>
</tbody>
</table>
<p>Para aprender más acerca de esta tradición puedes visitar las siguientes páginas</p>
<ul>
<li><a href="http://www.uv.mx/cienciahombre/revistae/vol25num1/articulos/altar/">http://www.uv.mx/cienciahombre/revistae/vol25num1/articulos/altar/</a></li>
<li><a href="http://www.mexicodesconocido.com.mx/haz-tu-propia-ofrenda-de-dia-de-muertos.html">http://www.mexicodesconocido.com.mx/haz-tu-propia-ofrenda-de-dia-de-muertos.html</a></li>
<li><a href="http://aristeguinoticias.com/2810/lomasdestacado/como-hacer-una-ofrenda-o-altar-de-muertos/">http://aristeguinoticias.com/2810/lomasdestacado/como-hacer-una-ofrenda-o-altar-de-muertos/</a></li>
</ul>
</article></body></html>

Pero nosotros no queremos todo el código. Por el momento sólo nos interesa el título de la página. Para esto primero debemos identificar en que etiquetas se encuentra esta información. En este caso las etiquetas que encierran la información que requerimos son title. Afortunadamente Beautiful Soup nos permite obtener esta información de manera relativamente sencilla.


In [25]:
titulo = soup.title.get_text()
print(titulo)


Día de muertos

Hemos obtenido el título.En la primer línea del código anterior hemos escrito title entre soup y get_text() porque de esta manera le indicamos al programa entre que etiquetas buscar. La función get_text() nos permite obtener sólo el texto entre las etiquetas que deseamos.

Segundo Ejemplo

Ya hemos obtenido el título de la página pero eso es muy sencillo. Ahora vamos a obtener las palabras en negritas del texto. Primero debemos identificar las etiquetas en las que se encuentran estas palabras. Las etiquetas son strong. Lamentablemente no podemos usar el método anterior porque sólo obtiene el texto de las primeras etiquetas que encuentra, no de el de todas con la misma etiqueta. Por lo tanto debemos usar otro método, para el cual usaremos la función de Beautiful Soup find_all().


In [26]:
palabrasclave = soup.find_all("strong")
print(palabrasclave)


[<strong>olmecas</strong>, <strong>mayas</strong>, <strong>aztecas</strong>, <strong>vida</strong>, <strong>muerte</strong>, <strong>ciclo</strong>, <strong>2</strong>, <strong>Noviembre</strong>]

Podemos ver que el nuevo método obtuvo todas las palabras que queríamos pero dejo las etiquetas de HTML y esas no nos sirve.


In [27]:
palabrascl = []
for indx, pacl in enumerate(palabrasclave):
    pacl = str(pacl.renderContents())
    pacl = pacl.replace("<strong>","")
    palabrascl.append(pacl)
print(palabrascl)


["b'olmecas'", "b'mayas'", "b'aztecas'", "b'vida'", "b'muerte'", "b'ciclo'", "b'2'", "b'Noviembre'"]

Definimos una lista palabrascl en la que guardaremos las palabras después de haber quitado el texto basura. Hemos quitado las etiquetas pero sigue quedando una b'. Agregaremos esto también en la función replace.


In [28]:
palabrascl = []
for indx, pacl in enumerate(palabrasclave):
    pacl = str(pacl.renderContents())
    pacl = pacl.replace("b'","")
    pacl = pacl.replace("'","")
    palabrascl.append(pacl)
print(palabrascl)


['olmecas', 'mayas', 'aztecas', 'vida', 'muerte', 'ciclo', '2', 'Noviembre']

Finalmente hemos obtenido sólo el texto de todas las palabras clave de la página.

Tercer Ejemplo

Ahora hagamos algo que puede ser muy útil para futuros scrappings, obtener los links dentro de una página web. Nuevamente debemos identificar las etiqutas donde se encuentran alojados los links. En el caso de los links esta etiqueta es a.


In [29]:
a = soup.find_all("a")
for indx, links in enumerate(a):
    print(indx,links.get('href'))


0 #d%C3%ADa-de-muertos
1 https://camo.githubusercontent.com/542dc43836a693c022132fbb103942c7fce4d1e1/687474703a2f2f7777772e7265706f7274616a65732e6f72672f77702d636f6e74656e742f75706c6f6164732f323031302f31312f64254333254144612d64652d6d756572746f732e6a7067
2 #elementos-escenciales-de-un-altar-de-muertos
3 http://www.uv.mx/cienciahombre/revistae/vol25num1/articulos/altar/
4 http://www.mexicodesconocido.com.mx/haz-tu-propia-ofrenda-de-dia-de-muertos.html
5 http://aristeguinoticias.com/2810/lomasdestacado/como-hacer-una-ofrenda-o-altar-de-muertos/

Los primeros tres links son genrados por defautl por Github.

Cuarto Ejemplo

Para este ejemplos buscaremos extraer la información de la tabla pero sólo los datos de la primer columna. De nuevo observando el código HTML nos damos cuenta de que la información que necesitamos se encuentran entre las etiquetas td pero a diferencia del texto de la segunda columna las etiquetas tienen un atributo "align = center". Podemos aprovechar esto a nuestro favor para indicarle al programa de una manera más específica que es lo que queremos que encuentre.


In [34]:
elementos = []
datostabla = soup.find_all("td",{"align" : "center"})
for indx, elem in enumerate(datostabla):
    elem = str(elem.renderContents())
    elem = elem.replace("b'","")
    elem = elem.replace("'","")
    elementos.append(elem)
print(elementos)


['Flor de Cempas\\xc3\\xbachil', 'Velas', 'Sal', 'Copal', 'Comida', 'Agua', 'Arco de flores']

En la función find_all() además de indicar la etiqueta que queremos que busque también agregamos el atibuto que tiene la primer columna a diferencia del ejemplo de las palabras clave en el que bastaba con indicar la etiqueta donde se encontraban las palabras.

Si no indicamos el atributo obtendríamos las dos columnas ya que el programa busca todo lo que se encuentra en la etiqueta td, por eso es importante aprovechar las clases y los atributos.