scrapy与selenium结合爬取数据(爬取动态网站)的示例代码


Posted in Python onSeptember 28, 2020

scrapy框架只能爬取静态网站。如需爬取动态网站,需要结合着selenium进行js的渲染,才能获取到动态加载的数据。

如何通过selenium请求url,而不再通过下载器Downloader去请求这个url?

方法:在request对象通过中间件的时候,在中间件内部开始使用selenium去请求url,并且会得到url对应的源码,然后再将   源 代码通过response对象返回,直接交给process_response()进行处理,再交给引擎。过程中相当于后续中间件的process_request()以及Downloader都跳过了。

相关的配置:

1、scrapy环境中安装selenium:pip install selenium

scrapy与selenium结合爬取数据(爬取动态网站)的示例代码

2、确保python环境中有phantomJS(无头浏览器)

scrapy与selenium结合爬取数据(爬取动态网站)的示例代码

对于selenium的主要操作是下载中间件部分如下图:

scrapy与selenium结合爬取数据(爬取动态网站)的示例代码

scrapy与selenium结合爬取数据(爬取动态网站)的示例代码

代码如下

middlewares.py代码:

注意:自定义下载中间件,采用selenium的方式!!

# -*- coding: utf-8 -*-

# Define here the models for your spider middleware
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/spider-middleware.html

from scrapy import signals
from selenium import webdriver
from selenium.webdriver import FirefoxOptions
from scrapy.http import HtmlResponse, Response
import time

class TaobaospiderSpiderMiddleware(object):
 # Not all methods need to be defined. If a method is not defined,
 # scrapy acts as if the spider middleware does not modify the
 # passed objects.

 @classmethod
 def from_crawler(cls, crawler):
  # This method is used by Scrapy to create your spiders.
  s = cls()
  crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
  return s

 def process_spider_input(self, response, spider):
  # Called for each response that goes through the spider
  # middleware and into the spider.

  # Should return None or raise an exception.
  return None

 def process_spider_output(self, response, result, spider):
  # Called with the results returned from the Spider, after
  # it has processed the response.

  # Must return an iterable of Request, dict or Item objects.
  for i in result:
   yield i

 def process_spider_exception(self, response, exception, spider):
  # Called when a spider or process_spider_input() method
  # (from other spider middleware) raises an exception.

  # Should return either None or an iterable of Response, dict
  # or Item objects.
  pass

 def process_start_requests(self, start_requests, spider):
  # Called with the start requests of the spider, and works
  # similarly to the process_spider_output() method, except
  # that it doesn't have a response associated.

  # Must return only requests (not items).
  for r in start_requests:
   yield r

 def spider_opened(self, spider):
  spider.logger.info('Spider opened: %s' % spider.name)


class TaobaospiderDownloaderMiddleware(object):
 # Not all methods need to be defined. If a method is not defined,
 # scrapy acts as if the downloader middleware does not modify the
 # passed objects.

 @classmethod
 def from_crawler(cls, crawler):
  # This method is used by Scrapy to create your spiders.
  s = cls()
  crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
  return s

 def process_request(self, request, spider):
  # Called for each request that goes through the downloader
  # middleware.

  # Must either:
  # - return None: continue processing this request
  # - or return a Response object
  # - or return a Request object
  # - or raise IgnoreRequest: process_exception() methods of
  # installed downloader middleware will be called
  return None

 def process_response(self, request, response, spider):
  # Called with the response returned from the downloader.

  # Must either;
  # - return a Response object
  # - return a Request object
  # - or raise IgnoreRequest
  return response

 def process_exception(self, request, exception, spider):
  # Called when a download handler or a process_request()
  # (from other downloader middleware) raises an exception.

  # Must either:
  # - return None: continue processing this exception
  # - return a Response object: stops process_exception() chain
  # - return a Request object: stops process_exception() chain
  pass

 def spider_opened(self, spider):
  spider.logger.info('Spider opened: %s' % spider.name)

*********************下面是相应是自定义的下载中间件的替换代码**************************
class SeleniumTaobaoDownloaderMiddleware(object):
 # 将driver创建在中间件的初始化方法中,适合项目中只有一个爬虫。
 # 爬虫项目中有多个爬虫文件的话,将driver对象的创建放在每一个爬虫文件中。
 # def __init__(self):
 #  # 在scrapy中创建driver对象,尽可能少的创建该对象。
 #  # 1. 在初始化方法中创建driver对象;
 #  # 2. 在open_spider中创建deriver对象;
 #  # 3. 不要将driver对象的创建放在process_request();
 #  option = FirefoxOptions()
 #  option.headless = True
 #  self.driver = webdriver.Firefox(options=option)

 # 参数spider就是TaobaoSpider()类的对象
 def process_request(self, request, spider):
  if spider.name == "taobao":
   spider.driver.get(request.url)
   # 由于淘宝的页面数据加载需要进行滚动,但并不是所有js动态数据都需要滚动。
   for x in range(1, 11, 2):
    height = float(x) / 10
    js = "document.documentElement.scrollTop = document.documentElement.scrollHeight * %f" % height
    spider.driver.execute_script(js)
    time.sleep(0.2)

   origin_code = spider.driver.page_source
   # 将源代码构造成为一个Response对象,并返回。
   res = HtmlResponse(url=request.url, encoding='utf8', body=origin_code, request=request)
   # res = Response(url=request.url, body=bytes(origin_code), request=request)
   return res
  if spider.name == 'bole':
   request.cookies = {}
   request.headers.setDefault('User-Agent','')
  return None

 def process_response(self, request, response, spider):
  print(response.url, response.status)
  return response

taobao.py 代码如下:

# -*- coding: utf-8 -*-
import scrapy
from selenium import webdriver
from selenium.webdriver import FirefoxOptions


class TaobaoSpider(scrapy.Spider):
 """
 scrapy框架只能爬取静态网站。如需爬取动态网站,需要结合着selenium进行js的渲染,才能获取到动态加载的数据。

 如何通过selenium请求url,而不再通过下载器Downloader去请求这个url?
 方法:在request对象通过中间件的时候,在中间件内部开始使用selenium去请求url,并且会得到url对应的源码,然后再将源代码通过response对象返回,直接交给process_response()进行处理,再交给引擎。过程中相当于后续中间件的process_request()以及Downloader都跳过了。

 """
 name = 'taobao'
 allowed_domains = ['taobao.com']
 start_urls = ['https://s.taobao.com/search?q=%E7%AC%94%E8%AE%B0%E6%9C%AC%E7%94%B5%E8%84%91&imgfile=&commend=all&ssid=s5-e&search_type=item&sourceId=tb.index&spm=a21bo.2017.201856-taobao-item.1&ie=utf8&initiative_id=tbindexz_20170306']
 
 def __init__(self):
  # 在初始化淘宝对象时,创建driver
  super(TaobaoSpider, self).__init__(name='taobao')
  option = FirefoxOptions()
  option.headless = True
  self.driver = webdriver.Firefox(options=option)

 def parse(self, response):
  """
  提取列表页的商品标题和价格
  :param response:
  :return:
  """
  info_divs = response.xpath('//div[@class="info-cont"]')
  print(len(info_divs))
  for div in info_divs:
   title = div.xpath('.//a[@class="product-title"]/@title').extract_first('')
   price = div.xpath('.//span[contains(@class, "g_price")]/strong/text()').extract_first('')
   print(title, price)

settings.py代码如下图:

scrapy与selenium结合爬取数据(爬取动态网站)的示例代码

关于代码中提到的初始化driver的位置有以下两种情况:

1、只存在一个爬虫文件的话,driver初始化函数可以定义在middlewares.py的自定义中间件中(如上述代码注释初始化部分)也可以在爬虫文件中自定义(如上述代码在爬虫文件中初始化)。

注意:如果只有一个爬虫文件就不需要在自定义的process_requsests中判断是哪一个爬虫项目然后分别请求!

2、如果存在两个或两个以上爬虫项目(如下图项目结构)的时候,需要将driver的初始化函数定义在各自的爬虫项目文件下(如上述代码),同时需要在process_requsests判断是那个爬虫项目的请求!!

scrapy与selenium结合爬取数据(爬取动态网站)的示例代码          

scrapy与selenium结合爬取数据(爬取动态网站)的示例代码

到此这篇关于scrapy与selenium结合爬取数据的示例代码的文章就介绍到这了,更多相关scrapy selenium爬取数据内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python中的类学习笔记
Sep 23 Python
Python中字典和JSON互转操作实例
Jan 19 Python
详解在Python中处理异常的教程
May 24 Python
使用Python的Twisted框架构建非阻塞下载程序的实例教程
May 25 Python
Python 专题二 条件语句和循环语句的基础知识
Mar 19 Python
Python科学计算包numpy用法实例详解
Feb 08 Python
使用Py2Exe for Python3创建自己的exe程序示例
Oct 31 Python
Pandas删除数据的几种情况(小结)
Jun 21 Python
Python lambda表达式filter、map、reduce函数用法解析
Sep 11 Python
python去除删除数据中\u0000\u0001等unicode字符串的代码
Mar 06 Python
python批量修改文件名的示例
Sep 27 Python
python中出现invalid syntax报错的几种原因分析
Feb 12 Python
scrapy结合selenium解析动态页面的实现
Sep 28 #Python
互斥锁解决 Python 中多线程共享全局变量的问题(推荐)
Sep 28 #Python
python 常见的反爬虫策略
Sep 27 #Python
python 5个实用的技巧
Sep 27 #Python
Python日志器使用方法及原理解析
Sep 27 #Python
python 爬取免费简历模板网站的示例
Sep 27 #Python
python如何提升爬虫效率
Sep 27 #Python
You might like
在wamp集成环境下升级php版本(实现方法)
2013/07/01 PHP
php实现URL加密解密的方法
2016/11/17 PHP
javascript 写类方式之十
2009/07/05 Javascript
Javascript 继承实现例子
2009/08/12 Javascript
Prototype源码浅析 Enumerable部分(二)
2012/01/18 Javascript
理解javascript中的回调函数(callback)
2014/09/02 Javascript
javascript实现禁止右键和F12查看源代码
2014/12/26 Javascript
jQuery寻找n以内完全数的方法
2015/06/24 Javascript
js实现跨域的4种实用方法原理分析
2015/10/29 Javascript
JavaScript编写Chrome扩展实现与浏览器的交互及时间通知
2016/05/16 Javascript
自己动手制作基于jQuery的Web页面加载进度条插件
2016/06/03 Javascript
jQuery实现的简单拖拽功能示例
2016/09/13 Javascript
JavaScript制作简易计算器(不用eval)
2017/02/05 Javascript
解决在Bootstrap模糊框中使用WebUploader的问题
2018/03/22 Javascript
vue中实现左右联动的效果
2018/06/22 Javascript
Vue 组件注册实例详解
2019/02/23 Javascript
js中的this的指向问题详解
2019/08/29 Javascript
vue-cli设置css不生效的解决方法
2020/02/07 Javascript
vue-router重写push方法,解决相同路径跳转报错问题
2020/08/07 Javascript
python 从远程服务器下载东西的代码
2013/02/10 Python
Python中几种操作字符串的方法的介绍
2015/04/09 Python
Python实现股市信息下载的方法
2015/06/15 Python
Python实现监控程序执行时间并将其写入日志的方法
2015/06/30 Python
Python数据类型详解(一)字符串
2016/05/08 Python
python对象及面向对象技术详解
2016/07/19 Python
pandas取出重复数据的方法
2019/07/04 Python
Python configparser模块应用过程解析
2020/08/14 Python
Django数据统计功能count()的使用
2020/11/30 Python
canvas实现漂亮的下雨效果的示例
2018/04/18 HTML / CSS
Mio Skincare英国官网:身体紧致及孕期身体护理
2018/08/19 全球购物
龟牌英国商店:Turtle Wax Brand Store UK
2019/07/02 全球购物
俄罗斯大型在线书店:Читай-город
2019/10/10 全球购物
英国儿童设计师服装和玩具购物网站:Zac & Lulu
2020/10/19 全球购物
单位承诺书格式
2014/05/21 职场文书
幼儿园大班区域活动总结
2014/07/09 职场文书
员工自我工作评价
2015/03/06 职场文书