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 相关文章推荐
使用IPython下的Net-SNMP来管理类UNIX系统的教程
Apr 15 Python
K-means聚类算法介绍与利用python实现的代码示例
Nov 13 Python
TensorFlow如何实现反向传播
Feb 06 Python
python实现雨滴下落到地面效果
Jun 21 Python
python实现小球弹跳效果
May 10 Python
在Python中构建增广矩阵的实现方法
Jul 01 Python
Python使用tkinter模块实现推箱子游戏
Oct 08 Python
Python实现图片添加文字
Nov 26 Python
python 实现按对象传值
Dec 26 Python
Django自定义全局403、404、500错误页面的示例代码
Mar 08 Python
Python异常类型以及处理方法汇总
Jun 05 Python
Python中的 No Module named ***问题及解决
Jul 23 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
php通过文件头检测文件类型通用代码类(zip,rar等)
2010/10/19 PHP
PHP判断远程url是否有效的几种方法小结
2011/10/08 PHP
浅析php学习的路线图
2013/07/10 PHP
PHP中fwrite与file_put_contents性能测试代码
2013/08/02 PHP
PHP实现微信商户支付企业付款到零钱功能
2018/09/30 PHP
微信公众平台开发教程④ ThinkPHP框架下微信支付功能图文详解
2019/04/10 PHP
js下获取div中的数据的原理分析
2010/04/07 Javascript
使用AngularJS来实现HTML页面嵌套的方法
2015/06/17 Javascript
url传递的参数值中包含&时,url自动截断问题的解决方法
2016/08/02 Javascript
bootstrap监听滚动实现头部跟随滚动
2016/11/08 Javascript
JS 循环li添加点击事件 (闭包的应用)
2016/12/10 Javascript
JS简单获取当前日期和农历日期的方法
2017/04/17 Javascript
vue.js的computed,filter,get,set的用法及区别详解
2018/03/08 Javascript
Vue2.0 v-for filter列表过滤功能的实现
2018/09/07 Javascript
javascript中的this作用域详解
2019/07/15 Javascript
layui自己添加图片按钮并点击跳转页面的例子
2019/09/14 Javascript
微信小程序实现上拉加载功能
2019/11/20 Javascript
pyqt4教程之实现windows窗口小示例分享
2014/03/07 Python
python爬取拉勾网职位数据的方法
2018/01/24 Python
Python使用gRPC传输协议教程
2018/10/16 Python
Python with用法:自动关闭文件进程
2019/07/10 Python
Java ExcutorService优雅关闭方式解析
2020/05/30 Python
python实现凯撒密码、凯撒加解密算法
2020/06/11 Python
css3动画鼠标放上图片逐渐变大鼠标离开图片逐渐缩小效果
2021/01/27 HTML / CSS
在IE6系列等老式浏览器中使用HTML5的新标签实现方案
2012/12/25 HTML / CSS
html5 worker 实例(一) 为什么测试不到效果
2013/06/24 HTML / CSS
为您搜罗全球潮流時尚品牌:HBX
2019/12/04 全球购物
英国哈罗德园艺:Harrod Horticultural
2020/03/31 全球购物
线程的基本概念、线程的基本状态以及状态之间的关系
2012/10/26 面试题
护理个人求职信范文
2014/01/08 职场文书
高二美术教学反思
2014/01/14 职场文书
离婚起诉书怎么写
2015/05/19 职场文书
利用ajax+php实现商品价格计算
2021/03/31 PHP
python数据分析之用sklearn预测糖尿病
2021/04/22 Python
为什么在foreach循环中JAVA集合不能添加或删除元素
2021/06/11 Java/Android
Redis基本数据类型Set常用操作命令
2022/06/01 Redis