Web Crawler | Expresiones regulares para el tutorial de introducción

Código fuente práctico para el desarrollo de rastreadores web: https://github.com/MakerChen66/Python3Spider

No es fácil ser original, el plagio y la reimpresión están prohibidos en este artículo, un resumen de años de experiencia práctica en el desarrollo de rastreadores, se debe investigar la infracción !

1. Introducción de expresiones regulares

¿Qué son las expresiones regulares?
Las expresiones regulares son una herramienta poderosa para procesar cadenas.Tienen su propia estructura gramatical y es fácil realizar la recuperación, el reemplazo y la verificación de coincidencias de cadenas. Para los rastreadores, es muy conveniente extraer la información deseada de HTML

Aplicación de expresiones regulares
Desarrollo de sitios web, desarrollo de rastreadores, desarrollo de juegos, desarrollo de bases de datos, etc. En resumen, las expresiones regulares se pueden usar siempre que contengan cadenas.

Importación de expresiones regulares
Las expresiones regulares tienen su propia biblioteca estándar en Python, no es necesario instalar, solo importar

import re



En segundo lugar, el uso de expresiones regulares.

Ejemplo de introducción
Abra el sitio web de prueba de expresiones regulares en línea proporcionado por Open Source China:
https://tool.oschina.net/regex/

Ingrese el carácter que desea hacer coincidir y luego seleccione una expresión regular común o escríbala usted mismo y podrá obtener el resultado de coincidencia correspondiente. Por ejemplo, ingrese el texto que se debe hacer coincidir aquí de la siguiente manera:

hello,my phone number is 010-85623654 and email is mackerchen@aliyun.com,and my website is https://makerchen.com

Esta cadena contiene el número de teléfono, el correo electrónico y la URL, y luego use expresiones regulares para extraerlo, como se muestra en la figura a continuación: Seleccione " Coincidir URL URL
inserte la descripción de la imagen aquí
" en el lado derecho de la página web , y podrá ver el texto en la parte inferior URL Si selecciona " Coincidir con la dirección de correo electrónico ", puede ver el correo electrónico en el texto a continuación

Todos estos utilizan la coincidencia de expresiones regulares, es decir, utilizan ciertas reglas para extraer texto específico . Por ejemplo, el comienzo de la URL es el tipo de protocolo, seguido de dos puntos y barras dobles, y finalmente el nombre de dominio y la ruta. Además, el correo electrónico comienza con una cadena, luego un símbolo @ y finalmente un nombre de dominio, que tiene un formato de composición específico.

Para las URL, se pueden usar las siguientes expresiones regulares para hacer coincidir:

[a-zA-z]+://[^\s]*

Use esta expresión regular para hacer coincidir una cadena, si la cadena contiene texto similar a la URL, se extraerá

Hay reglas gramaticales específicas en él . Por ejemplo, az significa hacer coincidir cualquier letra minúscula, \s significa hacer coincidir cualquier carácter en blanco, y el ^\s anterior significa hacer coincidir un carácter que no esté en blanco, que es igual a \S, y * significa hacer coincidir cualquier número de personajes anteriores

La siguiente tabla enumera las reglas de coincidencia más utilizadas:

\w Une letras, números y guiones bajos
\W Coincide con caracteres que no son letras, números y guiones bajos
\s Coincide con cualquier carácter de espacio en blanco, equivalente a [\t\n\r\f] y ^\S
\S Coincide con cualquier carácter que no esté vacío, equivalente a ^\s
\d Coincide con cualquier número, equivalente a [0-9]
\D coincide con cualquier carácter no numérico
\A coincide con el comienzo de la cadena
\Z Coincide con el final de la cadena, si hay una nueva línea, solo coincidirá con la cadena final antes de la nueva línea
\z Coincide con el final de la cadena, si hay una nueva línea, también coincidirá con la nueva línea
\GRAMO Partido donde se realizó el último partido
\norte coincide con una nueva línea
\t coincide con una pestaña
^ coincide con el comienzo de una línea de cadena
ps coincide con el final de una línea de cadena
. Coincide con cualquier carácter, excepto nueva línea, cuando se especifica el indicador re.DOTALL, puede coincidir con cualquier carácter, incluida la nueva línea
[…] Se utiliza para representar un grupo de caracteres, enumerados por separado, como [amk] coincide con a, m o k
[^…] Los caracteres que no están en [], como [^abc] coinciden con caracteres distintos de a, b, c
* coincide con 0 o más expresiones
+ coincide con 0 o más expresiones
? Coincide con 0 o 1 fragmento definido por la expresión regular anterior, no codicioso
{norte} Hacer coincidir exactamente n expresiones anteriores, como \d{10} significa hacer coincidir 10 números
{Nuevo Méjico} Hacer coincidir n a m veces el segmento definido por la expresión regular anterior, codicioso
a b
() coincide con una expresión encerrada entre paréntesis, que también denota un grupo

Después de leerlo, puede que te sientas un poco mareado, no te preocupes, más adelante explicaremos en detalle el uso de las reglas comunes

: Del mismo modo, los rastreadores también se pueden implementar en otros lenguajes de programación , como Java, pero la biblioteca de rastreadores proporcionada por Python es mucho más rica que otros lenguajes de programación.

3. Método de emparejamiento

3.1 partido()

En primer lugar, introduzca el primer método de coincidencia de uso común: match(), que tiene dos parámetros formales, que son la expresión regular y la cadena que debe coincidir.

El método match() coincide con la expresión regular desde el principio de la cadena y devuelve el resultado si la coincidencia es exitosa, de lo contrario, devuelve Ninguno. El ejemplo es el siguiente:

import re

content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
result = re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}', content)
print(result)
print(result.group())
print(result.span())

La salida es la siguiente:

41
<_sre.SRE_Match object; span=(0, 25), match='Hello 123 4567 World_This'>
Hello 123 4567 World_This
(0, 25)

(^Hola\s\d\d\d\s\d{4}\s\w{10})
Utilice la expresión regular anterior para hacer coincidir esta larga cadena. El ^ al principio es el principio de la cadena coincidente, es decir, comienza con Hola; luego \s coincide con un carácter en blanco; \d coincide con un número, 3 \ds coincide con 123; luego escribe 1 \s para coincidir con un espacio ; hay 4567 detrás, de hecho, todavía podemos usar 4 \d para hacer coincidir, pero es engorroso escribirlo de esta manera, por lo que puede ir seguido de {4} para representar la coincidencia de la regla anterior 4 veces, es decir, la coincidencia 4 números; y luego seguido de 1 carácter en blanco, el último \w{10} coincide con 10 letras y guiones bajos. Nos dimos cuenta de que la cadena de destino no se ha emparejado aquí, pero aún se puede hacer coincidir de esta manera, pero el resultado de la coincidencia es más corto.

En la impresión, puede ver que el resultado es un objeto SRE_Match, lo que prueba una coincidencia exitosa. Este objeto tiene dos métodos: el método group() puede generar el contenido coincidente y el resultado es Hello 123 4567 World_This, que resulta ser el contenido coincidente con la regla de expresión regular; el método span() puede generar el rango coincidente, y el resultado es (0, 25), este es el rango de posición de la cadena de resultado coincidente en la cadena original

3.2 buscar()

Como se mencionó anteriormente, el método match() comienza a hacer coincidir desde el principio de la cadena . Una vez que el método de coincidencia no coincida al principio, la coincidencia completa fallará. Aquí hay otro método de búsqueda (), que escanea toda la cadena cuando coincide y luego devuelve el primer resultado de coincidencia exitoso , o devuelve Ninguno si no se encuentra después de la búsqueda.

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result = re.search('Hello.*?(\d+).*?Demo', content)
print(result)

La salida es la siguiente:

<_sre.SRE_Match object; span=(13, 53), match='Hello 1234567 World_This is a Regex Demo'>

Para la conveniencia de hacer coincidir, tratamos de usar el método search(). Si cambia la búsqueda en el código anterior para que coincida, el resultado será Ninguno

3.3 buscar todo()

El método search() mencionado anteriormente devolverá el primer contenido que coincida con la expresión regular, pero si queremos obtener todo el contenido que coincida con la expresión regular, debemos usar el método findall() El ejemplo es el siguiente:

import re

html = '''<div id="songs-list">
    <h2 class="title">经典老歌</h2>
    <p class="introduction">
        经典老歌列表
    </p>
    <ul id="list" class="list-group">
        <li data-view="2">一路上有你</li>
        <li data-view="7">
            <a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
        </li>
        <li data-view="4" class="active">
            <a href="/3.mp3" singer="齐秦">往事随风</a>
        </li>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="邓丽君">但愿人长久</a>
        </li>
    </ul>
</div>'''

Si queremos obtener los hipervínculos, los cantantes y los títulos de las canciones de todos los nodos en el texto HTML anterior, podemos reemplazar el método search() con el método findall(), y el resultado devuelto es un tipo de lista, que debe ser atravesado para obtener cada grupo en el contenido de la lista, el código es el siguiente:

results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S)
print(results)
print(type(results))
for result in results:
    print(result)
    print(result[0], result[1], result[2])

Los resultados de salida son los siguientes: como
inserte la descripción de la imagen aquí
puede ver, el tipo devuelto por el método findall() es "lista", y cada elemento de la lista es un tipo de tupla, que se puede recuperar con el índice correspondiente

3.4 sub()

Usamos expresiones regulares para extraer información y, a veces, necesitamos modificar el texto . En este momento, podemos usar el método sub(), que tiene la misma función que el método replace(), pero el uso es diferente y el replace () es más engorroso, por lo que se recomienda utilizar el método sub() . Los ejemplos son los siguientes:

import re

content = '54aK54yr5oiR54ix5L2g'
content = re.sub('\d+', '', content)
print(content)

El método sub() tiene tres parámetros formales, el primero es una expresión regular que indica el contenido que se va a comparar, el segundo parámetro es la cadena que se va a reemplazar (puede estar vacía) y el tercer parámetro es la cadena original. Lo anterior significa reemplazar el número con vacío, es decir, eliminar el número

La salida es la siguiente:

aKyroiRixLg



3.5 compilar()

Todos los métodos mencionados anteriormente se utilizan para procesar cadenas.Finalmente, presentaremos el método compile(), que puede convertir cadenas de expresión regular en objetos de expresión regular para reutilizarlos en coincidencias posteriores.

Los ejemplos son los siguientes:

import re

content1 = '2016-12-15 12:00'
content2 = '2016-12-17 12:55'
content3 = '2016-12-22 13:21'
pattern = re.compile('\d{2}:\d{2}')
result1 = re.sub(pattern, '', content1)
result2 = re.sub(pattern, '', content2)
result3 = re.sub(pattern, '', content3)
print(result1, result2, result3)

Hay 3 fechas aquí, y queremos eliminar la hora de las 3 fechas respectivamente. En este momento, podemos usar el método sub(). El primer parámetro de este método es una expresión regular, pero no es necesario escribir tres expresiones regulares iguales repetidamente. En este momento, puede usar el método compile() para compilar la expresión regular en un objeto de expresión regular para su reutilización.

La salida es la siguiente:

2016-12-152016-12-172016-12-22

Además, compile() también puede pasar modificadores, como re.S y otros modificadores, por lo que no es necesario pasar métodos adicionales como search() y findall(). Entonces, se puede decir que el método compile() es una capa de encapsulación para expresiones regulares para que podamos reutilizarlas mejor.


4. Modo de coincidencia

4.1 Partido objetivo

En el método de coincidencia, podemos usar el método match() para obtener el contenido de la cadena coincidente, pero ¿qué pasa si queremos extraer parte del contenido de la cadena? Al igual que en el ejemplo anterior, extraiga contenido como correo electrónico o número de teléfono de un texto

Aquí puede usar corchetes () para encerrar la subcadena que desea extraer. () en realidad marca la posición inicial y final de una subexpresión. Cada subexpresión marcada corresponderá a cada grupo a su vez. Llame al método group() para pasar el índice del grupo para obtener el resultado extraído. Los ejemplos son los siguientes:

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld', content)
print(result)
print(result.group())
print(result.group(1))
print(result.span())

Aquí queremos extraer de la cadena 1234567. En este momento, podemos encerrar la expresión regular de la parte numérica con (), y luego llamar al grupo (1) para obtener el resultado coincidente

La salida es la siguiente:

<_sre.SRE_Match object; span=(0, 19), match='Hello 1234567 World'>
Hello 1234567 World
1234567
(0, 19)

Como puede ver, obtuvimos con éxito 1234567, aquí está el grupo (1), que es diferente del grupo (), este último generará el resultado de coincidencia completo, mientras que el primero generará la primera coincidencia rodeada por () resultado. Si hay contenido incluido en () después de la expresión regular, puede usar group(2), group(3), etc. para obtener

4.2 Coincidencia universal

La expresión regular que acabamos de escribir es en realidad más complicada. Si hay un carácter en blanco, escribiremos \s para que coincida, y si hay un número, usaremos \d para que coincida. Este tipo de carga de trabajo es muy pesada. De hecho, no hay necesidad de hacer esto en absoluto, porque hay otra coincidencia universal que se puede usar, es decir, (punto estrella). Entre ellos, (punto) puede coincidir con cualquier carácter (excepto el carácter de nueva línea, (estrella) significa coincidir con el carácter anterior un número ilimitado de veces, por lo que se pueden combinar para coincidir con cualquier carácter . Con él, no tenemos que hacer coincidir los caracteres uno por uno. uno

Siguiendo el ejemplo anterior, podemos reescribir la expresión regular:

import re

content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^Hello.*Demo$', content)
print(result)
print(result.group())
print(result.span())

Omitimos la parte del medio directamente y la reemplazamos con .*, y agregamos una cadena final al final. El resultado es el siguiente:

<_sre.SRE_Match object; span=(0, 41), match='Hello 123 4567 World_This is a Regex Demo'>
Hello 123 4567 World_This is a Regex Demo
(0, 41)

El método group() genera todas las cadenas coincidentes, es decir, la expresión regular que escribimos coincide con todo el contenido de la cadena de destino; el método span() genera (0, 41), que es la longitud de la cadena completa

Por lo tanto, podemos usar .* para simplificar la escritura de expresiones regulares

4.3 Codiciosos y no codiciosos

Al usar la coincidencia general anterior.*, a veces el resultado de la coincidencia puede no ser el que queremos. como sigue:

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*(\d+).*Demo$', content)
print(result)
print(result.group(1))

Aquí todavía queremos obtener el número en el medio, por lo que (\d+) todavía se escribe en el medio. Dado que el contenido en ambos lados del número es desordenado, quiero omitirlo y escribirlo como . Finalmente, la composición de ^He. (\d+).*Demo$ parece ser la misma. Veamos la salida:

<_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
7

Suceden cosas extrañas, solo obtenemos el número 7, ¿qué está pasando?

Esto implica un problema de emparejamiento codicioso y no codicioso. Con la coincidencia codiciosa, .* coincide con tantos caracteres como sea posible . En la expresión regular, .* va seguido de \d+, es decir, al menos un número y no se especifica ningún número específico. Por lo tanto, .* coincide con tantos caracteres como sea posible. Aquí, 123456 coincide, dejando \d+ Un número 7 que cumple las condiciones, y el contenido final es solo el número 7

Pero obviamente va a ser un gran inconveniente para nosotros. A veces, los resultados coincidentes inexplicablemente perderán algún contenido. De hecho, solo necesita usar la coincidencia no codiciosa aquí. El método de escritura de la coincidencia no codiciosa es .*? , uno extra? Entonces, ¿qué efecto puede lograr?

Veámoslo de nuevo con un ejemplo:

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\d+).*Demo$', content)
print(result)
print(result.group(1))

Simplemente convertimos . en . ?, lo que se convierte en una coincidencia no codiciosa. La salida es la siguiente:

<_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
1234567

En este punto, 1234567 se puede obtener con éxito. La razón se puede imaginar, la coincidencia codiciosa es hacer coincidir la mayor cantidad de caracteres posible, y la coincidencia no codiciosa es hacer coincidir la menor cantidad de caracteres posible . Cuando . ? coincide con el carácter en blanco después de Hola, los siguientes caracteres son números y \d+ puede coincidir, por lo que aquí .? no coincidirá y \d+ se usará para coincidir con los siguientes números. Así que de esta manera.*? coincide con la menor cantidad de caracteres posible, y el resultado de \d+ es 1234567

Por lo tanto, cuando haga coincidencias, intente usar coincidencias no codiciosas en el medio de la cadena, es decir, use . ? para reemplazar para evitar perder resultados coincidentes

Pero aquí debe prestar atención, si el resultado coincidente está al final de la cadena, es posible que .* ?

4.4 Modificadores

Una expresión regular puede contener algunos modificadores de bandera opcionales para controlar el patrón coincidente. Los ejemplos son los siguientes:

import re

content = '''Hello 1234567 World_This
is a Regex Demo
'''
result = re.match('^He.*?(\d+).*?Demo$', content)
print(result.group(1))

Similar al ejemplo anterior, acabamos de agregar un carácter de nueva línea en la cadena, y la expresión regular sigue siendo la misma, utilizada para hacer coincidir los números en ella. Eche un vistazo a la salida:

AttributeError: 'NoneType' object has no attribute 'group'

La operación informa directamente un error, es decir, la expresión regular no coincide con la cadena, y el resultado devuelto es Ninguno, y llamamos al método group() para causar AttributeError

Entonces, ¿por qué no puede coincidir después de agregar un carácter de nueva línea? Esto se debe a que la coincidencia es cualquier carácter excepto un carácter de nueva línea. Cuando se encuentra un carácter de nueva línea, no se puede hacer coincidir .*?, por lo que la coincidencia falla. Aquí solo necesitas agregar un modificador re.S para corregir este error:

result = re.match('^He.*?(\d+).*?Demo$', content,re.S)

La función de este modificador es hacer coincidir todos los caracteres, incluidas las líneas nuevas. En este punto la salida es la siguiente:

1234567

re.S se usa a menudo en la coincidencia de páginas web. Debido a que los nodos HTML a menudo tienen líneas nuevas, agregarlo puede hacer coincidir las líneas nuevas entre los nodos

Además, existen algunos modificadores, como se muestra en la siguiente tabla:

re yo Hacer que coincidan mayúsculas y minúsculas
re.L Coincidencia de identificación de localización
movimiento rápido del ojo Coincidencia multilínea, afecta a ^ y $
re.S hacer coincidir todos los caracteres, incluidas las líneas nuevas
re.U Los caracteres se analizan de acuerdo con el conjunto de caracteres Unicode, lo que afecta a \w, \W, \b, \B
re.X Dar un formato de expresión regular más flexible

4.5 emparejamiento de escape

Muchos modos de coincidencia se definen en expresiones regulares, como .coincide con todos los caracteres, incluidos los caracteres de nueva línea, pero ¿qué debemos hacer si la cadena de destino contiene .

En este momento, debe usar la coincidencia de escape, como se muestra a continuación:

import re

content = '(百度)www.baidu.com'
result = re.match('\(百度\)www\.baidu\.com', content)
print(result)

Cuando encuentre un carácter especial utilizado en un patrón de coincidencia regular, simplemente agregue una barra invertida para escapar. Aquí use para hacer coincidir, la salida es la siguiente:

<_sre.SRE_Match object; span=(0, 17), match='(百度)www.baidu.com'>

Como puede ver, la cadena original coincide con éxito aquí

Estos son patrones de coincidencia comunes para escribir expresiones regulares, dominarlos es muy útil para escribir coincidencias de expresiones regulares.

4.6 Conclusión

Hasta ahora, se ha introducido el uso básico de las expresiones regulares. Más adelante, se utilizarán ejemplos específicos para explicar el uso de las expresiones regulares, incluido el uso de expresiones regulares para rastrear datos de películas Maoyan, datos de monjes en formación, etc. Consulte los artículos prácticos correspondientes a los rastreadores web.


5. Enlace al texto original

Enlace al texto original de mi cuenta pública original: leer el texto original

La originalidad no es fácil, si lo encuentras útil, espero que puedas darle un pulgar hacia arriba, ¡gracias chicos!

6. Información del autor

Autor: Xiaohong's Fishing Daily, Objetivo: ¡Hacer la programación más interesante!

Cuenta pública original de WeChat: " Tecnología Xiaohong Xingkong ", centrada en algoritmos, rastreadores, sitios web, desarrollo de juegos, análisis de datos, procesamiento de lenguaje natural, IA, etc. Esperamos su atención, ¡crezcamos y codifiquemos juntos!

Instrucciones de reimpresión: ¡Este artículo prohíbe el plagio y la reimpresión, y los infractores serán procesados!

Supongo que te gusta

Origin blog.csdn.net/qq_44000141/article/details/121457192
Recomendado
Clasificación