我想减少代码完成抓取页面所需的时间,我正在使用 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,但仍然遇到了同样的问题,没有得到页面中的所有文章。
电子邮件地址受 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
}
将 time.sleep(1) 替换为:
WebDriverWait(驱动程序, 10).until(EC.presence_of_element_ located((By.XPATH, 'your_xpath_here')))
使用 cProfile 来识别代码中的瓶颈。优化脚本中较慢的部分。
使用 python 的“多处理”库创建同时抓取不同页面的并行进程。
Scrapy 和 Selenium 一起使用效率更高。 Scrapy 可以处理初始页面导航,然后您可以切换到 Selenium 来执行特定任务,例如处理 JavaScript 渲染的内容等等......