scrapy,selenium 不会返回页面中的所有元素

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

我想减少代码完成抓取页面所需的时间,我正在使用 selenium。 我在这个抓取项目中使用了 Scrapy,但 JavaScript 隐藏了 Scrapy 中的电子邮件元素。

Scrapy 很完美,我不知道是否有办法减少 selenium 的时间,或者有其他方法,或者在这种情况下使用其他工具或包?

如果有任何信息或文档可以了解更多信息,我将不胜感激。

这是代码:

import scrapy
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from urllib.parse import urljoin
from selenium.webdriver import Chrome
import time


def decode_email_protection(encoded_string):
    if encoded_string:
        encoded_data = encoded_string.split('#')[-1]

        r = int(encoded_data[:2], 16)
        email = ''.join([chr(int(encoded_data[i:i + 2], 16) ^ r) for i in range(2, len(encoded_data), 2)])

        encoded_data = email.split('#')[-1]

        r = int(encoded_data[4:6], 16)
        encoded_data = encoded_data[:4] + encoded_data[6:]
        email = ''.join([chr(int(encoded_data[i:i + 2], 16) ^ r) for i in range(0, len(encoded_data), 2)])
        return email
    else:
        return None

class ExampleSpider(scrapy.Spider):
    name = "example_spider"
    allowed_domains = ["mdpi.com"]
    base_url = "https://www.mdpi.com/search?q=biomaterials"
    pages_scraped = 0

    def start_requests(self):
        # Using Selenium to render JavaScript content
        path = r"C:\Users\HP\Desktop\scraping\chromedriver.exe"
        options = Options()
        options.headless=True
        driver =Chrome(executable_path=path, options=options)
        driver.get(self.base_url)

        # Extracting all article links
        article_links = driver.find_elements(By.XPATH, "//a[@class='title-link']")
        print("Number of article links:", len(article_links))
        for link in article_links:
            yield scrapy.Request(url=link.get_attribute('href'), callback=self.parse_article)
        print("Number of article links:", len(article_links))
        # Closing the Selenium driver
        driver.quit()

    def parse_article(self, response):
        self.pages_scraped += 1
        title = response.xpath("//h1[contains(@class,'title')]/text()").get(default="").strip()
        authors = response.xpath("//a[@class='profile-card-drop'][1]//text()").get(default="").strip()
        email_href = response.xpath("//a[contains(@class,'email')]/@href").get(default="")
        email = decode_email_protection(email_href)

        yield {
            "Title": title,
            "Link": response.url,
            "Authors": authors,
            "Email": email
        }

编辑: 这是代码的新版本,感谢@SuperUser。 现在的问题是 scrapy 每页返回 15 篇文章,而应该是 50 篇文章。 我使用 scrapy shell,我看到article_href 方法返回 15 个链接。 我尝试并寻找原因,但一无所获。 即使我认为问题出在scrapy中,所以我确实使用了selenium,但仍然遇到了同样的问题,没有得到页面中的所有文章。

python performance selenium-webdriver web-scraping scrapy
2个回答
1
投票

电子邮件地址受 CloudFlare 的电子邮件保护脚本保护(实际上是双重编码)。我在网上找到了解码脚本,但它是针对单个编码字符串的,所以我必须修改它。

以下是如何使用 Scrapy(无硒)抓取网站:

编辑:添加动态分页以在单个页面上获取所有项目。

import scrapy
import logging


def decode_email_protection(encoded_string):
    encoded_data = encoded_string.split('#')[-1]

    r = int(encoded_data[:2], 16)
    email = ''.join([chr(int(encoded_data[i:i + 2], 16) ^ r) for i in range(2, len(encoded_data), 2)])

    encoded_data = email.split('#')[-1]

    r = int(encoded_data[4:6], 16)
    encoded_data = encoded_data[:4] + encoded_data[6:]
    email = ''.join([chr(int(encoded_data[i:i + 2], 16) ^ r) for i in range(0, len(encoded_data), 2)])
    return email


class ExampleSpider(scrapy.Spider):
    name = "example_spider"
    allowed_domains = ["mdpi.com"]
    base_url = "https://www.mdpi.com/search?sort=pubdate&page_no={}&page_count=50&year_from=1996&year_to=2024&q=biomaterials&view=default"

    def start_requests(self):
        for page_no in range(218, 219):
            yield scrapy.Request(url=self.base_url.format(page_no), cb_kwargs={"page_no": page_no, "index": 0})

    def parse(self, response, page_no, index):
        self.log(f"Scraping page number : {page_no}", logging.INFO)
        article_hrefs = response.xpath("//a[@class='title-link']/@href").getall()
        for href in article_hrefs:
            yield response.follow(url=href, callback=self.parse_page)

        if index < 50//15:     # 1 page with 15 articles plus 3 others = 50 items in total
            index += 1
            headers = {
                "X-Requested-With": "XMLHttpRequest",
                "Referer": self.base_url.format(page_no),
                "USER_AGENT": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36',
            }
            yield scrapy.Request(url='https://www.mdpi.com/search/set/default/pagination', headers=headers, cb_kwargs={"page_no": page_no, "index": index}, dont_filter=True)

    def parse_page(self, response):
        self.log(f"Scraping article: {response.url}", logging.INFO)

        title = response.xpath("//h1[contains(@class,'title')]//text()").getall()
        title = "".join(i.strip() for i in title)
        authors = response.xpath("//a[@class='profile-card-drop']//text()").getall()
        authors = [i.strip() for i in authors]
        email_href = response.xpath("//a[contains(@class,'email')]/@href").get(default="")
        email = decode_email_protection(email_href)

        yield {
            "Title": title,
            "Link": response.url,
            "Authors": authors,
            "Email": email
        }

0
投票

将 time.sleep(1) 替换为:

WebDriverWait(驱动程序, 10).until(EC.presence_of_element_ located((By.XPATH, 'your_xpath_here')))

使用 cProfile 来识别代码中的瓶颈。优化脚本中较慢的部分。

使用 python 的“多处理”库创建同时抓取不同页面的并行进程。

Scrapy 和 Selenium 一起使用效率更高。 Scrapy 可以处理初始页面导航,然后您可以切换到 Selenium 来执行特定任务,例如处理 JavaScript 渲染的内容等等......

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