这个代码中可能有两个原因导致无法爬取到 parse_detail
中的数据:
- 在调用
SeleniumRequest
时,没有将当前页面的 HTML 内容传递给HtmlResponse
对象。这会导致在parse_detail
中使用 XPath 无法获取到页面元素。
解决方法:可以通过下面的代码在 parse_detail
方法中创建一个新的 HtmlResponse
对象,并将当前页面的 HTML 内容传递给它。
html = driver.page_source.encode('utf-8')
response_obj = scrapy.http.HtmlResponse(url=driver.current_url, body=html)
然后,就可以使用 response_obj.xpath()
方法来提取页面元素了。
- 在等待元素可见时,使用了错误的 XPath 表达式。这可能导致等待超时或者找不到目标元素。
解决方法:建议首先手动打开需要爬取的网页,在浏览器中检查需要提取的元素,然后复制其 XPath 表达式并粘贴到代码中。另外,也可以尝试使用其他定位方式(如 CSS Selector 等)来定位目标元素。
修改后的代码如下所示:
import scrapy
import time
from ..items import JournalsItem, JournalsDetailItem, JournalCoverItem
from scrapy.linkextractors import LinkExtractor
from scrapy_selenium import SeleniumRequest
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.wait import WebDriverWait
class CnkiSpider(scrapy.Spider):
name = 'cnki'
allowed_domains = ['navi.cnki.net']
start_urls = ['https://navi.cnki.net/knavi/journals/index']
PAGE_MAX = 290 # only 290 pages of journals have an impact factor
def __init__(self):
self.driver = webdriver.Chrome()
def parse(self, response):
self.driver.get(response.url)
time.sleep(2)
self.driver.find_element(By.XPATH,'//*[@id="rightnavi"]/ul/li[2]/a')
time.sleep(5)
html = self.driver.page_source.encode('utf-8')
response_obj = scrapy.http.HtmlResponse(url=self.driver.current_url, body=html)
for journal in response_obj.xpath('//div[@class="detials"]'):
ji = JournalsItem()
ji['name'] = journal.xpath('.//h1/text()').extract_first().strip()
ji['composite_if'] = journal.xpath('.//p/text()').extract_first().strip()
yield ji
le = LinkExtractor(restrict_xpaths='//ul[@class="list_tup"]/li/a[@target="_blank"]')
d_urls = le.extract_links(response)
for d_url in d_urls:
yield SeleniumRequest(url=d_url.url, callback=self.parse_detail,
wait_time=10,
wait_sleep=2,)
def parse_detail(self, response):
driver = response.request.meta['driver']
# 创建新的 HtmlResponse 对象
html = driver.page_source.encode('utf-8')
response_obj = scrapy.http.HtmlResponse(url=driver.current_url, body=html)
# 等待目标元素可见
wait = WebDriverWait(driver, 10)
# 使用正确的 XPath 表达式
wait.until(ec.visibility_of_all_elements_located((By.XPATH, '//img[@class="el-image__inner el-image__preview"]')))
# 释放驱动程序
response.release_driver()
jd_item = JournalsDetailItem()
jd_item['name'] = response_obj.xpath('//h3[@class="titbox titbox1"]/text()').extract_first().strip()
jd_item['institute'] = response_obj.xpath('//ul[@id="JournalBaseInfo"]/li/span/text()').extract_first().strip()
jd_item['total_publications'] = response_obj.xpath('//ul[@id="publishInfo"]/li/span/text()').extract_first().strip()
yield jd_item
def close(self, reason):
self.driver.quit()
需要注意的是,代码中的 SeleniumRequest
类需要从 scrapy_selenium
模块中导入。另外,在等待目标元素可见时,要确保使用正确的 XPath 表达式或其他定位方式来定位目标元素。