Conceptos básicos del rastreador de Python (5): uso del marco scrapy

Directorio de artículos

Índice de artículos de la serie

Conceptos básicos del rastreador de Python (1): explicación detallada del uso de la biblioteca urllib.
Conceptos básicos del rastreador de Python (2): uso de xpath y jsonpath para analizar datos rastreados.
Conceptos básicos del rastreador de Python (3): uso de Selenium para cargar páginas web dinámicamente.
Conceptos básicos del rastreador de Python (4) : Más conveniente para usar los conceptos básicos del rastreador de Python de la biblioteca de solicitudes
(5): uso del marco scrapy

1. Introducción a scrapy

1. ¿Qué es scrapy?

Scrapy es un marco de aplicación escrito para rastrear datos de páginas web y extraer datos estructurados. El marco está encapsulado e incluye solicitudes (programación y procesamiento asincrónicos), descargador (descargador multiproceso), analizador (selector) y retorcido (procesamiento asincrónico), etc. Para el rastreo de contenido de sitios web, su velocidad es muy rápida.

2. instalación deficiente

# 进入到python安装目录的Scripts目录
d:
cd D:\python\Scripts
# 安装 可以使用国内源
pip install scrapy

3. Composición de arquitectura scrapy

(1) Motor: se ejecuta automáticamente, no es necesario prestar atención, organizará automáticamente todos los objetos solicitados y los distribuirá a los descargadores.
(2) Descargador: después de obtener el objeto de solicitud del motor, solicite los datos.
(3) Arañas: la clase araña define cómo rastrear un determinado (o determinado) sitio web. Incluye acciones de rastreo (por ejemplo: seguir enlaces) y cómo extraer datos estructurados del contenido de las páginas web (elementos de rastreo). En otras palabras, Spider es el lugar donde se definen las acciones de rastreo y se analiza una página web.
(4) Programador: tiene sus propias reglas de programación, no es necesario prestarle atención.
(5) Canalización (canalización de elementos): la canalización que finalmente procesa los datos reservará interfaces para que procesemos los datos. Una vez que el artículo se recopila en Spider, se pasará a la canalización de artículos y algunos componentes realizarán el procesamiento del artículo en un orden determinado. Cada componente de la canalización de elementos es una clase de Python que implementa métodos simples. Reciben el elemento y realizan algunas acciones a través de él. También deciden si el elemento continúa pasando por la canalización o se descarta sin procesar.

Las siguientes son algunas aplicaciones típicas de la canalización de elementos:
(1) Limpiar datos HTML, (2) Verificar los datos rastreados (verificar que el elemento contenga ciertos campos), (3) Verificar duplicaciones (y descartar), (4) Convertir los resultados rastreados se guardan en la base de datos.

4. Cómo funciona Scrapy

arañas->programador (programador)->motor scrapy (motor)->descargador (descargador)->Descargar de Internet->
Datos descargados del motor a arañas->Análisis de datos a través del motor xpath->Usar canalización para almacenamiento de datos

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

2. Uso básico de scrapy

1. Crea un proyecto

Ingrese al directorio del proyecto y abra cmd:

# 创建scrapy_test_001项目,项目名不能以数字、汉字开头
scrapy startproject scrapy_test

2. Cree un archivo de rastreo

Para crear un archivo de rastreador en la carpeta de arañas

# cd 项目的名字\项目的名字\spiders
cd scrapy_test\scrapy_test\spiders

Cree un archivo de rastreador. Tenga en cuenta que no es necesario agregar el protocolo http:

# scrapy genspider 爬虫文件的名字  要爬取网页
scrapy genspider baidu  www.baidu.com

En este momento, se generará un baidu.py en el directorio de arañas:
Insertar descripción de la imagen aquí
Echemos un vistazo al contenido de baidu.py:

import scrapy

class BaiduSpider(scrapy.Spider):
    # 爬虫的名字  用于运行爬虫的时候 使用的值
    name = "baidu"
    # 允许访问的域名
    allowed_domains = ["www.baidu.com"]
    # 起始的url地址  指的是第一次要访问的域名
    start_urls = ["https://www.baidu.com"]

    # 是执行了start_urls之后 执行的方法   方法中的response 就是返回的那个对象
    # 相当于 response = urllib.request.urlopen()
    #       response  = requests.get()
    def parse(self, response):
        pass

Más tarde, podemos procesar la respuesta en el método de análisis, que es el resultado final del rastreo.

3. (Adjunto) Composición del proyecto

Insertar descripción de la imagen aquí

4. Ejecute el código del rastreador.

(1) Modificar baidu.py

En el método de análisis, personalice la salida:

def parse(self,response):
    print('输出正确!')

En el directorio de arañas, ejecute el siguiente comando para ejecutar el código del rastreador:

# scrapy crawl 爬虫的名字
scrapy crawl baidu

Se generará una gran cantidad de contenido, pero no imprimimos nada.

(2) archivo de robots

En la consola, está impreso el protocolo del robot de Baidu:
Insertar descripción de la imagen aquí

Cada sitio web tendrá un acuerdo de caballeros sobre robots, que define lo que no se permite rastrear. Veamos los robots de Baidu:
https://www.baidu.com/robots.txt

En el archivo settings.py del proyecto, el valor predeterminado es ROBOTSTXT_OBEY=True, lo que significa seguir este acuerdo de caballeros.

Sólo necesitamos comentar esta línea:
Insertar descripción de la imagen aquí
en este punto ejecutaremos el código del rastreador:

# scrapy crawl 爬虫的名字
scrapy crawl baidu

En este momento, en la línea de comando, se imprimirá nuestra oración personalizada.

5. Atributos y métodos de respuesta

Response.xpath (xpath_expression): selecciona y extrae datos según la expresión XPath.
Response.css (css_expression): selecciona y extrae datos según los selectores CSS.
respuesta.follow (url): crea una nueva solicitud basada en la URL proporcionada y continúa procesando a través del método de devolución de llamada.
respuesta.url: devuelve la URL de la respuesta actual.
respuesta.status: Devuelve el código de estado de la respuesta actual.
Response.headers: devuelve la información del encabezado de la respuesta actual.
respuesta.cuerpo: devuelve el contenido binario sin formato de la respuesta actual.
respuesta.texto: devuelve el contenido de texto de la respuesta actual.
Response.css('a::attr(href)').getall(): utilice el selector CSS para extraer todos los valores de atributos de elementos coincidentes.
Response.xpath('//a/@href').extract(): utilice expresiones XPath para extraer todos los valores de atributos de elementos coincidentes.

6. Combate práctico: obtenga el contenido del botón [Baidu Click] de Baidu

Insertar descripción de la imagen aquí

    def parse(self, response):
        print('=====================')
        input = response.xpath('//input[@id="su"]/@value')[0]
        print(input.extract()) # 百度一下
        print('=====================')

7. Combate práctico: Obtenga la lista de precios de automóviles Autohome

Insertar descripción de la imagen aquí

import scrapy

class CarSpider(scrapy.Spider):
    name = 'car'
    allowed_domains = ['https://car.autohome.com.cn/price/brand-15.html']
    start_urls = ['https://car.autohome.com.cn/price/brand-15.html']

    def parse(self, response):
        print('=======================')
        name_list = response.xpath('//div[@class="main-title"]/a/text()')
        price_list = response.xpath('//div[@class="main-lever"]//span/span/text()')

        for i in range(len(name_list)):
            name = name_list[i].extract()
            price = price_list[i].extract()
            print(name,price)
        print('=======================')

3. Utilice cáscara raspada

1. ¿Qué es la concha raspada?

La terminal scrapy es una terminal interactiva para que pueda intentar depurar su código de rastreo sin iniciar la araña. Está diseñado para probar código que extrae datos, pero puede usarlo como un terminal Python normal y probar cualquier código Python en él.

Este terminal se utiliza para probar expresiones xPath o CSS para ver cómo funcionan y extraer datos de páginas web rastreadas. Al escribir su araña, la terminal brinda la capacidad de probar interactivamente su código de expresión, eliminando el problema de ejecutar la araña después de cada modificación. Una vez que se familiarice con la terminal scrapy, descubrirá que desempeña un papel muy importante en el desarrollo y depuración de arañas.

2. Instale ipython (opcional)

# 进入到python安装目录的Scripts目录
d:
cd D:\python\Scripts
# 安装 可以使用国内源
pip install ipython

Si IPython está instalado, el terminal scrapy utilizará IPython (en lugar del terminal Python estándar). El terminal IPython es más potente que otros y proporciona autocompletado inteligente, salida resaltada y otras funciones.

Uso: Ingrese ipython directamente en la línea de comando y la nueva ventana de comando tendrá su propio resaltado y autocompletado:
Insertar descripción de la imagen aquí

3. Utilice cáscara raspada

# 直接在window的终端中输入scrapy shell 域名
# 直接在命令终端(不需要进入python或者ipython终端),执行完毕之后,自动进入ipython终端
scrapy shell www.baidu.com

El objeto de respuesta se puede obtener y depurar directamente aquí.
Insertar descripción de la imagen aquí

4. Combate práctico: obtención de datos de productos de Dangdang.com

1. Inicializar proyecto

# 在自定义目录中创建项目
scrapy startproject scrapy_dangdang

# 创建爬虫文件
# cd 项目的名字\项目的名字\spiders
cd scrapy_dangdang\scrapy_dangdang\spiders

# scrapy genspider 爬虫文件的名字  要爬取网页
# 中国古典小说网址:http://category.dangdang.com/cp01.03.32.00.00.00.html
scrapy genspider dang http://category.dangdang.com/cp01.03.32.00.00.00.html

# 运行
scrapy crawl dang

2. Definir archivo de artículo

En item.py generado automáticamente por el proyecto, defina el formato de datos que se rastreará:

import scrapy

class ScrapyDangdangItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    # 通俗的说就是你要下载的数据都有什么,固定写法:scrapy.Field()

    # 图片
    src = scrapy.Field()
    # 名字
    name = scrapy.Field()
    # 价格
    price = scrapy.Field()

3. Rastrear imágenes, nombres y precios.

Insertar descripción de la imagen aquí
Primero analicemos el xpath de estos tres:
Obtenga el xpath de la imagen: //ul[@id="component_59"]/li/a/img/@srcdebido a que la imagen se carga de forma diferida, se deben obtener los atributos de la imagen data-original.
Insertar descripción de la imagen aquí
Obtener el xpath del título: //ul[@id="component_59"]/li/p[@class="name"]/a/@title
Insertar descripción de la imagen aquí
Obtener el xpath del precio://ul[@id="component_59"]/li/p[@class="price"]/span[1]/text()
Insertar descripción de la imagen aquí

import scrapy

class DangSpider(scrapy.Spider):
    name = "dang"
    allowed_domains = ["category.dangdang.com"]
    start_urls = ["http://category.dangdang.com/cp01.03.32.00.00.00.html"]

    def parse(self, response):
        #         src = //ul[@id="component_59"]/li/a/img/@src
        #         name = //ul[@id="component_59"]/li/p[@class="name"]/a/@title
        #         price = //ul[@id="component_59"]/li/p[@class="price"]/span[1]/text()
        #         所有的seletor的对象 都可以再次调用xpath方法
        li_list = response.xpath('//ul[@id="component_59"]/li')

        for li in li_list:
            src = li.xpath('./a/img/@data-original').extract_first()
            # 第一张图片和其他的图片的标签的属性是不一样的
            # 第一张图片的src是可以使用的  其他的图片的地址是data-original
            if src:
                src = src
            else:
                src = li.xpath('./a/img/@src').extract_first()

            name = li.xpath('./p[@class="name"]/a/@title').extract_first()
            price = li.xpath('./p[@class="price"]/span[1]/text()').extract_first()
            # 拿到所有信息
            print(src + name + price)

4. Embalaje de tuberías

(1) Familiarizado con el rendimiento

Una función vinculada ya no es una función ordinaria, sino un generador que puede usarse para iteración.

rendimiento es una palabra clave similar a retorno. Cuando la iteración encuentra rendimiento, devuelve el valor después del rendimiento (lado derecho). El punto es: en la siguiente iteración, la ejecución comienza desde el código (siguiente línea) después del rendimiento encontrado por el iterador anterior.

Comprensión simple: rendimiento significa que retorno devuelve un valor y recuerda la posición devuelta, y la siguiente iteración comenzará desde esta posición (siguiente línea).

(2) Construya el objeto del artículo y entréguelo a la tubería.

Arriba hemos obtenido la imagen, el nombre y el precio, continuamos construyendo el objeto del artículo en el método de análisis y lo entregamos a la canalización:

from scrapy_dangdang.items import ScrapyDangdangItem
            # 构造item对象
            book = ScrapyDangdangItem(src=src,name=name,price=price)

            # 获取一个book就将book交给pipelines
            yield book

(3) Habilitar canalización en settings.py

Puede haber muchas canalizaciones, por lo que las canalizaciones tienen prioridades. El rango de prioridad es de 1 a 1000. Cuanto menor sea el valor, mayor será la prioridad.

ITEM_PIPELINES = {
    
    
    #  管道可以有很多个  那么管道是有优先级的  优先级的范围是1到1000   值越小优先级越高
   "scrapy_dangdang.pipelines.ScrapyDangdangPipeline": 300,
}

(4) Editar canalización.py

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html

# useful for handling different item types with a single interface
from itemadapter import ItemAdapter

# 如果想使用管道的话 那么就必须在settings中开启管道
class ScrapyDangdangPipeline:
    # 在爬虫文件开始的之前就执行的一个方法 :open_spider
    def open_spider(self,spider):
        self.fp = open('book.json','w',encoding='utf-8')

    # 执行过程:process_item
    # item就是yield后面的book对象
    def process_item(self, item, spider):
        # 以下这种模式不推荐  因为每传递过来一个对象 那么就打开一次文件  对文件的操作过于频繁

        # # (1) write方法必须要写一个字符串 而不能是其他的对象
        # # (2) w模式 会每一个对象都打开一次文件 覆盖之前的内容
        # with open('book.json','a',encoding='utf-8')as fp:
        #     fp.write(str(item))

        self.fp.write(str(item))
        self.fp.write('\n')

        return item

    # 在爬虫文件执行完之后  执行的方法 : close_spider
    def close_spider(self,spider):
        self.fp.close()

(5) Ejecute y vea el archivo json escrito

scrapy crawl dang

5. Uso de múltiples tuberías

(1)pipelines.py define la clase de canalización

Se pueden definir varias clases en pipelines.py, simplemente escríbalas directamente.
Hay tres métodos predeterminados en la clase que se pueden usar directamente.

import urllib.request
class ScrapyDangdangDownloadPipeline:
    def process_item(self, item, spider):
        url = 'http:' + item.get('src')
        filename = './books/' + item.get('name') + '.jpg'
        urllib.request.urlretrieve(url = url, filename= filename)
        # 有返回值
        return item

(2) settings.py abre la canalización

ITEM_PIPELINES = {
    
    
    #  管道可以有很多个  那么管道是有优先级的  优先级的范围是1到1000   值越小优先级越高
   "scrapy_dangdang.pipelines.ScrapyDangdangPipeline": 300,

   'scrapy_dangdang.pipelines.ScrapyDangdangDownloadPipeline':301
}

(5) Ejecute y vea las imágenes y los archivos json escritos.

Primero cree el directorio de libros en arañas.

# 执行
scrapy crawl dang

6. Obtenga varias páginas de datos

import scrapy
from scrapy_dangdang.items import ScrapyDangdangItem


class DangSpider(scrapy.Spider):
    name = "dang"
    allowed_domains = ["category.dangdang.com"]
    start_urls = ["http://category.dangdang.com/cp01.03.32.00.00.00.html"]

    base_url = 'http://category.dangdang.com/cp'
    page = 1
    def parse(self, response):
		# 。。。省略


#       每一页的爬取的业务逻辑全都是一样的,所以我们只需要将执行的那个页的请求再次调用parse方法
# 就可以了
#         http://category.dangdang.com/pg2-cp01.03.32.00.00.00.html
#         http://category.dangdang.com/pg3-cp01.03.32.00.00.00.html
#         http://category.dangdang.com/pg4-cp01.03.32.00.00.00.html

        if self.page < 100:
            self.page = self.page + 1

            url = self.base_url + str(self.page) + '-cp01.03.32.00.00.00.html'

#             怎么去调用parse方法
#             scrapy.Request就是scrpay的get请求
#             url就是请求地址
#             callback是你要执行的那个函数  注意不需要加()
            yield scrapy.Request(url=url,callback=self.parse)


5. Combate práctico: Obtención de datos de diferentes páginas de Movie Paradise

1. Efecto

Obtenga Movie Paradise, el nombre de la película en la lista de la primera página:
Insertar descripción de la imagen aquí
luego haga clic en los detalles de la película y luego obtenga la imagen en los detalles de la segunda página:
Insertar descripción de la imagen aquí

2. Código central

código central mv.py

import scrapy

from scrapy_movie_099.items import ScrapyMovie099Item

class MvSpider(scrapy.Spider):
    name = 'mv'
    allowed_domains = ['www.dygod.net']
    start_urls = ['https://www.dygod.net/html/gndy/china/index.html']

    def parse(self, response):
#         要第一个的名字 和 第二页的图片
        a_list = response.xpath('//div[@class="co_content8"]//td[2]//a[2]')

        for a in a_list:
            # 获取第一页的name 和 要点击的链接
            name = a.xpath('./text()').extract_first()
            href = a.xpath('./@href').extract_first()

            # 第二页的地址是
            url = 'https://www.dygod.net' + href

            # 对第二页的链接发起访问 并将name参数传入
            yield  scrapy.Request(url=url,callback=self.parse_second,meta={
    
    'name':name})

    def parse_second(self,response):
        # 注意 如果拿不到数据的情况下  一定检查你的xpath语法是否正确
        src = response.xpath('//div[@id="Zoom"]//img/@src').extract_first()
        # 接受到请求的那个meta参数的值
        name = response.meta['name']

        movie = ScrapyMovie099Item(src=src,name=name)

        yield movie

tuberías.py:

from itemadapter import ItemAdapter

class ScrapyMovie099Pipeline:

    def open_spider(self,spider):
        self.fp = open('movie.json','w',encoding='utf-8')

    def process_item(self, item, spider):

        self.fp.write(str(item))
        return item

    def close_spider(self,spider):
        self.fp.close()

Abra la canalización en settings.py:

ITEM_PIPELINES = {
    
    
   'scrapy_movie_099.pipelines.ScrapyMovie099Pipeline': 300,
}

6. Combate práctico: utilice CrawlSpider para obtener datos de Dudu.com

1. Introducción a CrawlSpider

CrawlSpider hereda de scrapy.Spider y puede definir reglas. Al analizar el contenido HTML, puede extraer enlaces específicos de acuerdo con las reglas de enlace y luego enviar solicitudes a estos enlaces.

Por lo tanto, si es necesario realizar un seguimiento del enlace, es decir, después de rastrear la página web, debe extraer el enlace y rastrearlo nuevamente, usar CrawlSpider es muy adecuado.

Sintaxis común para extraer enlaces :
extractor de enlaces, donde puede escribir reglas para extraer enlaces específicos:

scrapy.linkextractors.LinkExtractor(
	allow = (), # 正则表达式,提取符合正则的链接
	deny = (), # (不用)正则表达式 不提取符合正则的链接
	allow_domains = (), # (不用)允许的域名
	deny_domains = (), # (不用)不允许的域名
	restrict_xpaths = (), # xpath,提取符合xpath规则的链接
	restrict_css = () # 提取符合选择器规则的链接
)

# 使用实例
# 正则用法:
links = LinkExtractor(allow = r'list_23_\d+\.html')
# xpath:
links = LinkExtractor(restrict_xpaths = r'//div[@class="x"]')
# css用法:
links = LinkExtractor(restrict_css='.x')

# 提取链接
links.extract_links(response)

2. Crea un proyecto

# 创建项目:scrapy startproject 项目的名字
scrapy startproject readbook

# 创建爬虫文件
# cd 项目名字\项目名字\spiders
cd readbook/readbook/Spiders
# scrapy genspider -t crawl 爬虫文件的名字  爬取的域名
scrapy genspider -t crawl read www.dushu.com/book/1188_1.html

Descubrimos que el contenido de read.py era diferente al que teníamos antes:
Insertar descripción de la imagen aquí

3. Definir artículo

class ReadbookItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    name = scrapy.Field()
    src = scrapy.Field()

4. Extraer datos

Insertar descripción de la imagen aquí

leer.py:

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from readbook.items import ReadbookItem

class ReadSpider(CrawlSpider):
    name = "read"
    allowed_domains = ["www.dushu.com"]
    # 注意,第一个url也要匹配规则!不然会跳过第一页
    start_urls = ["https://www.dushu.com/book/1188_1.html"]

    # 规则
    rules = (Rule(LinkExtractor(allow=r"/book/1188_\d+.html"), callback="parse_item", follow=True),)

    # 解析
    def parse_item(self, response):
        img_list = response.xpath('//div[@class="bookslist"]//img')

        for img in img_list:
            name = img.xpath('./@data-original').extract_first()
            src = img.xpath('./@alt').extract_first()

            book = ReadbookItem(name=name,src=src)
            yield book

5. Definir canalización

# settings.py
ITEM_PIPELINES = {
    
    
   "readbook.pipelines.ReadbookPipeline": 300,
}
# pipelines.py
from itemadapter import ItemAdapter

class ReadbookPipeline:
    def open_spider(self,spider):
        self.fp = open('book.json','w',encoding='utf-8')

    def process_item(self, item, spider):
        self.fp.write(str(item))
        return item

    def close_spider(self,spider):
        self.fp.close()

6. Empezar

 scrapy crawl read

Después de la ejecución, vea el archivo book.json.

7. Guardar en mysql

Instalar pymysql:

# 进入到python安装目录的Scripts目录
d:
cd D:\python\Scripts
# 安装 可以使用国内源
pip install pymysql

Agregar una canalización:

# settings.py
ITEM_PIPELINES = {
    
    
   "readbook.pipelines.ReadbookPipeline": 300,
   # MysqlPipeline
   'readbook.pipelines.MysqlPipeline':301
}
# 参数中一个端口号 一个是字符集 都要注意
DB_HOST = '192.168.1.1'
# 端口号是一个整数
DB_PORT = 3306
DB_USER = 'root'
DB_PASSWROD = '123'
DB_NAME = 'spider01'
# utf-8的杠不允许写
DB_CHARSET = 'utf8'

tuberías.py:

# 加载settings文件
from scrapy.utils.project import get_project_settings
import pymysql


class MysqlPipeline:

    def open_spider(self,spider):
        settings = get_project_settings()
        self.host = settings['DB_HOST']
        self.port =settings['DB_PORT']
        self.user =settings['DB_USER']
        self.password =settings['DB_PASSWROD']
        self.name =settings['DB_NAME']
        self.charset =settings['DB_CHARSET']

        self.connect()

    def connect(self):
        self.conn = pymysql.connect(
                            host=self.host,
                            port=self.port,
                            user=self.user,
                            password=self.password,
                            db=self.name,
                            charset=self.charset
        )

        self.cursor = self.conn.cursor()


    def process_item(self, item, spider):

        sql = 'insert into book(name,src) values("{}","{}")'.format(item['name'],item['src'])
        # 执行sql语句
        self.cursor.execute(sql)
        # 提交
        self.conn.commit()
        return item

    def close_spider(self,spider):
        self.cursor.close()
        self.conn.close()

7. Combate práctico: envío de solicitud de publicación.

Clave:

import scrapy

import json

class TestpostSpider(scrapy.Spider):
    name = 'testpost'
    allowed_domains = ['https://fanyi.baidu.com/sug']
    # post请求 如果没有参数 那么这个请求将没有任何意义
    # 所以start_urls 也没有用了
    # parse方法也没有用了
    # start_urls = ['https://fanyi.baidu.com/sug/']
    #
    # def parse(self, response):
    #     pass



	# start_requests是一个固定方法
    def start_requests(self):
        url = 'https://fanyi.baidu.com/sug'

        data = {
    
    
            'kw': 'final'
        }

        yield scrapy.FormRequest(url=url,formdata=data,callback=self.parse_second)

    def parse_second(self,response):

        content = response.text
        obj = json.loads(content,encoding='utf-8')

        print(obj)

Supongo que te gusta

Origin blog.csdn.net/A_art_xiang/article/details/132807935
Recomendado
Clasificación