导入必要的模块
import scrapy import re import time from ..items import JournalsItem, JournalsDetailItem, JournalCoverItem # 导入定义好的数据结构 from scrapy.linkextractors import LinkExtractor # 导入链接提取器 from scrapy_selenium import SeleniumRequest # 导入Selenium请求处理器 from selenium import webdriver # 导入selenium中webdriver驱动程序接口,用于启动浏览器并与之交互。 from selenium.webdriver.common.by import By # 对于一个网页,可以使用多种方法定位元素。WebDriver 提供了8种主要的定位方式:
ID、Name、Class Name、Tag Name、Link Text、Partial Link Text、CSS Selector和XPath。
这里是导入其中一种。
from selenium.webdriver.support import expected_conditions as ec # 通过预期条件来判断某个元素是否已经加载出来。
# 如我们可以在页面上判断某个元素是否存在,然后再执行其他操作,
# 或者等待元素变成可点击状态后再进行下一步操作。
# 这里是将其重命名为ec方便调用。
from selenium.webdriver.support.wait import WebDriverWait
class CnkiSpider(scrapy.Spider):
name = 'cnki' # 爬虫名称
start_urls = ['https://navi.cnki.net/knavi/journals/index'] # 开始爬取的url列表
PAGE_MAX = 5 # 最大爬取页数(在获取期刊数据时需要设置为290)
page = 1 # 当前爬取的页数
def __init__(self):
self.driver = webdriver.Chrome() # 启动Chrome浏览器驱动程序
def parse(self, response):
self.driver.get(response.url) # 使用webdriver打开网站
time.sleep(2) # 等待页面加载完毕
# 在页面上找到"期刊"并点击
self.driver.find_element('xpath','//*[@id="rightnavi"]/ul/li[2]/a').click()
html = self.driver.page_source.encode('utf-8') # 获取当前网页源代码,以utf-8编码返回。
# 对于没有正确设置字符集的页面,也可以通过此方法获得正确的内容。
response_obj = scrapy.http.HtmlResponse(url=self.driver.current_url, body=html) # 将获取到的网页源代码封装成Scrapy响应对象。
for journal in response_obj.xpath('//ul[@class="list_tup"]/li'):
ji = JournalsItem() # 创建JournalsItem对象
ji['name'] = journal.xpath('.//h1/text()').extract_first().strip()
ji['composite_if'] = journal.xpath('.//p/text()').extract_first().strip()
ji['deurl']='https://navi.cnki.net'+journal.xpath('.//a/@href').extract_first().strip()
yield SeleniumRequest(
url = ji['deurl'], # 要访问的URL
callback = self.parse_detail, # 请求成功后调用的回调函数
wait_time = 10, # 等待页面加载时间
wait_sleep = 2, # 每次等待时间间隔
meta = {'driver': self.driver,'ji':ji}) # 将webdriver和JournalsItem对象作为meta参数传递给回调函数
while self.page < self.PAGE_MAX:
driver.execute_script('arguments[0].click();', driver.find_elements(By.XPATH, '//*[@id="rightnavi"]/div[2]/a[@class="next"]')[0])
time.sleep(5)
html = self.driver.page_source.encode('utf-8')
response_obj = scrapy.http.HtmlResponse(url=driver.current_url, body=html)
for journal in response_obj.xpath('//ul[@class="list_tup"]/li'):
ji = JournalsItem()
ji['name'] = journal.xpath('.//h1/text()').extract_first().strip()
ji['composite_if'] = journal.xpath('.//p/text()').extract_first().strip()
ji['deurl']='https://navi.cnki.net'+journal.xpath('.//a/@href').extract_first().strip()
yield SeleniumRequest(
url = ji['deurl'],
callback = self.parse_detail,
wait_time = 10,
wait_sleep = 2,
meta = {'driver': driver,'ji':ji})
self.page+=1
def parse_detail(self, response):
driver = response.request.meta['driver']
html = driver.page_source.encode('utf-8')
journal_obj = scrapy.http.HtmlResponse(url=driver.current_url, body=html)
wait = WebDriverWait(driver, 10) # 设置等待时间,超时抛出异常TimeoutException。
# 在等待时间内如果元素被找到了,则继续执行;否则就一直等到超时为止。
jd_item=response.request.meta['ji']
jd_item['name'] = response.xpath('//h3[@class="titbox titbox1"]/text()').extract_first().strip()
jd_item['institute'] = response.xpath('//ul[@id="JournalBaseInfo"]/li//span/text()').extract_first().strip()
jd_item['c_time'] = re.findall('创刊时间</label>:<span>(.*?)</span></p>',response.text)[0]
jd_item['total_publications'] = response.xpath(
'//ul[@id="publishInfo"]/li//p[@class="hostUnit"]/span/text()').extract_first().strip()
yield jd_item
def close(self, reason):
self.driver.quit() # 关闭浏览器驱动程序。