andrewwf 2020-05-30
由于简书中一些数据是通过js渲染出来的,所以通过正常的request请求返回的response源码中没有相关数据,
所以这里选择selenium+webdriver获取网页源码
import scrapy class JianshuItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() author = scrapy.Field() author_img = scrapy.Field() time = scrapy.Field() read_count = scrapy.Field() subjects = scrapy.Field()
from scrapy import signals from scrapy.http.response.html import HtmlResponse from selenium import webdriver # 显示等待 from selenium.webdriver.support.ui import WebDriverWait class SeleniumDownloaderMiddleware: def __init__(self): # 加载chrome驱动,若chromedriver.exe文件和python.exe 在相同目录下,可以省略executable_path="D:\python\chromedriver.exe" # 即 self.driver=webdriver.Chrome()就可以 self.driver = webdriver.Chrome(executable_path="D:\python\chromedriver.exe") def process_request(self, request, spider): print("-"*40) print(id(self)) print("-"*40) self.driver.get(request.url) try: while True: WebDriverWait(self.driver, 3).until(lambda x: x.find_element_by_class_name("H7E3vT")) # 获取加载更多按钮 # show_more = self.driver.find_element_by_xpath("//div[@class=‘H7E3vT‘]") show_more = self.driver.find_element_by_class_name("H7E3vT") show_more.click() except: print("找不到更多按钮") pass # 获取网页源代码 html = self.driver.page_source # 使用url=self.driver.current_url而不使用url=request.url,是有可能发生重定向,导致url发生变化 response = HtmlResponse(url=self.driver.current_url, body=html, request=request, encoding="utf-8") # 返回response,请求就直接返回给scrapy引擎,而不会再发给下载器执行下载 return response
# -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from scrapylearn.jianshu.jianshu.items import JianshuItem class JianshuspiderSpider(CrawlSpider): name = ‘jianshuspider‘ allowed_domains = [‘jianshu.com‘] start_urls = [‘http://jianshu.com/‘] rules = ( Rule(LinkExtractor(allow=r‘.*/p/[0-9a-z]{12}.*‘), callback=‘parse_detail‘, follow=True), ) def parse_detail(self, response): title = response.xpath("//h1[@class=‘_1RuRku‘]/text()").get() author = response.xpath("//span[@class=‘FxYr8x‘]/a/text()").get() author_img = response.xpath("//img[@class=‘_13D2Eh‘]/@src").get() time = response.xpath("//div[@class=‘s-dsoj‘]/time/text()").get() read_count = response.xpath("//div[@class=‘s-dsoj‘]/span[2]/text()").get().split()[1].replace(",", "") subjects = ",".join(response.xpath("//div[@class=‘_2Nttfz‘]/a/span/text()").getall()) yield JianshuItem(title=title, author=author, author_img=author_img, time=time, read_count=read_count, subjects=subjects) def parse_item(self, response): item = {} # item[‘domain_id‘] = response.xpath(‘//input[@id="sid"]/@value‘).get() # item[‘name‘] = response.xpath(‘//div[@id="name"]‘).get() # item[‘description‘] = response.xpath(‘//div[@id="description"]‘).get() return item
import pymysql class JianshuPipeline: def __init__(self): self.conn = pymysql.connect( host=‘localhost‘, port=3307, user=‘root‘, password=‘1612480331‘, database=‘houses‘, charset=‘utf8‘ ) def process_item(self, item, spider): print("=" * 40) print(id(self)) print("=" * 40) # 打开数据库连接 # conn = pymysql.connect("localhost", "root", "1612480331", "houses", 3307) # 创建一个游标对象 cursor = self.conn.cursor() sql = "insert into jianshu values (%s,%s,%s,%s,%s,%s)" cursor.execute(sql, ( item["title"], item["author"], item["author_img"], item["time"], item["read_count"], item["subjects"])) self.conn.commit() # print(values) # for v in values: # print(v) cursor.close() return item # 当爬虫关闭的时候会调用 def close_spider(self, spider): self.conn.close() print("爬虫执行结束")
DOWNLOADER_MIDDLEWARES = { # ‘jianshu.middlewares.JianshuDownloaderMiddleware‘: 543, ‘jianshu.middlewares.SeleniumDownloaderMiddleware‘: 1 } ITEM_PIPELINES = { ‘jianshu.pipelines.JianshuPipeline‘: 300, } USER_AGENT = ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36‘ # Obey robots.txt rules ROBOTSTXT_OBEY = False