没有 <a> 节点/href 属性的 Scrapy web

问题描述 投票:0回答:1

相信你做得很好! 我需要您的支持,我正在尝试抓取此网页:https://servicio.mapa.gob.es/regfiweb# 进入后,您必须前往:

  1. 巴士多。
  2. 产品。

我想下载所有pdf文件,但没有带有href属性的节点。相反,有一些带有 data-id 的按钮,通过 javascript 触发来启动 pdf 下载。

我尝试过但完全不成功。

你有什么想法吗?

我想逐页导航并下载每页的 pdf。

我的代码:

import scrapy


class SimpleSpider(scrapy.Spider):
    name = "simple"
    # allowed_domains = ["x"]
    start_urls = ["https://servicio.mapa.gob.es/regfiweb#"]
    
    def parse(self, response):
        for book in response.css('.col'):
            title = book.css('span ::text').get()
            link = response.urljoin(
                # book.css('a.pdf ::attr(href)').get()
                book.css('a::attr(href)').get()
            )
            yield {
                'Title': title,
                'file_urls': [link]
            }
web-scraping scrapy scrapy-splash
1个回答
1
投票

如果您打开 devtools 并转到网络选项卡,您可以看到“产品”页面的 url。您可以前往此处,填写表格并提交。 DevTools

如果您停留在页面上并点击搜索按钮,您可以看到页面如何请求结果。我发现这更容易,这就是我要做的。你可以看到最后的数字,对我来说它看起来像 unix 时间戳。 Search page url

您可以验证它(例如使用 cyberchef)。 cyberchef unix timestamp

如果我们检查 pdf 下载按钮,我们会看到:

function(n) {
  n.stopImmediatePropagation();
  n.stopPropagation();
  n.preventDefault();
  var i = $("#exportFichaProductoPdf").val(),
    t = {};
  t.idProducto = parseInt(this.dataset.id);
  exportPdf(i, t)
}

查找

exportPdf
函数后,您会发现:

exportPdf = function (n, t) {
        $.ajax({
            url: n,
            data: { dataDto: t },
            type: 'POST',
            xhrFields: { responseType: 'blob' },
            success: function (n, t, i) {
                var s, u;
                console.log(n);
                var e = new Blob([n], { type: 'application/pdf' }), r = document.createElement('a'), o = '', f = i.getResponseHeader('Content-Disposition');
                f && f.indexOf('attachment') !== -1 && (s = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/, u = s.exec(f), u != null && u[1] && (o = u[1].replace(/['"]/g, '')));
                /^((?!chrome|android).)*safari/i.test(navigator.userAgent) ? window.open(window.URL.createObjectURL(e), '_blank') : (r.href = window.URL.createObjectURL(e), r.target = '_blank', r.download = o, document.body.appendChild(r), r.click());
            },
            beforeSend: function () {
                $('#loadingDiv').show();
            },
            complete: function () {
                $('#loadingDiv').hide();
            },
            error: function (n) {
                console.log(n.status);
                console.log(n.responseText);
                var t = document.createElement('div');
                t.innerHTML = 'En este momentos el documento no está disponible, estamos trabajando para que pueda obtenerlo lo antes posible.';
                swal({
                    title: 'Documento no disponible',
                    content: t,
                    icon: 'warning'
                });
            }
        });
    }

所以基本上我们需要一个 url 和 id,以便我们可以重新创建请求:

import scrapy
import os
import time


def get_timestamp_ms():
    return int(time.time() * 1000)


class SimpleSpider(scrapy.Spider):
    name = "simple"
    allowed_domains = ["servicio.mapa.gob.es"]
    base_url = "https://servicio.mapa.gob.es/regfiweb/Productos/ProductosGrid?NombreComercial=&Titular=&NumRegistro=&Fabricante=&IdSustancia=-1&IdEstado=1&IdAmbito=undefined&IdPlaga=-1&IdFuncion=-1&IdCultivo=-1&IdSistemaCultivo=-1&IdTipoUsuario=-1&AncestrosCultivos=false&AncestrosPlagas=false&FecRenoDesde=&FecRenoHasta=&FecCaduDesde=&FecCaduHasta=&FecModiDesde=&FecModiHasta=&FecInscDesde=&FecInscHasta=&FecLimiDesde=&FecLimiHasta=&productosGrid-page={}&_={}"
    base_dir = "downloads"

    def start_requests(self):
        page = 1
        yield scrapy.Request(url=self.base_url.format(str(page), str(get_timestamp_ms())), cb_kwargs={'page': page})

    def parse(self, response, page):
        from scrapy.shell import open_in_browser
        open_in_browser(response)
        for book in response.xpath('//tr[not(ancestor::thead)]'):
            title = book.xpath('./td[5]//text()').get(default="")
            file_id = book.xpath('./td[last()]/button/@data-id').get()
            if file_id:
                yield scrapy.FormRequest(url="https://servicio.mapa.gob.es/regfiweb/Productos/ExportFichaProductoPdf", formdata={"idProducto": file_id}, method="POST", cb_kwargs={"title": f"{title}_{file_id}"}, callback=self.download_pdf, dont_filter=True)

        # pagination
        page += 1
        num_pages = response.xpath('//button[@data-page][last()]/@data-page').get(default=0)
        if page < int(num_pages):
            yield scrapy.Request(url=self.base_url.format(str(page), str(get_timestamp_ms())), cb_kwargs={'page': page})

    def download_pdf(self, response, title):
        filename = os.path.join(self.base_dir, title+".pdf")
        with open(filename, 'wb') as f:
            f.write(response.body)

在运行代码之前,您需要确保

base_dir
存在。

这只是一个示例,您可能需要添加分页和搜索查询。

© www.soinside.com 2019 - 2024. All rights reserved.