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 相关文章推荐
pip 错误unused-command-line-argument-hard-error-in-future解决办法
Jun 01 Python
python实现多线程采集的2个代码例子
Jul 07 Python
python打开网页和暂停实例
Sep 30 Python
如何解决django配置settings时遇到Could not import settings 'conf.local'
Nov 18 Python
python抓取最新博客内容并生成Rss
May 17 Python
Django如何配置mysql数据库
May 04 Python
用python爬取租房网站信息的代码
Dec 14 Python
python+selenium 定位到元素,无法点击的解决方法
Jan 30 Python
对Pytorch神经网络初始化kaiming分布详解
Aug 18 Python
Python实现线性插值和三次样条插值的示例代码
Nov 13 Python
Python实现猜年龄游戏代码实例
Mar 25 Python
pytorch加载预训练模型与自己模型不匹配的解决方案
May 13 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
phpMyAdmin 安装教程全攻略
2007/03/19 PHP
php 分页函数multi() discuz
2009/06/21 PHP
PHP 文件上传源码分析(RFC1867)
2009/10/30 PHP
PHP图像处理之使用imagecolorallocate()函数设置颜色例子
2014/11/19 PHP
如何直接访问php实例对象中的private属性详解
2017/10/12 PHP
事件模型在各浏览器中存在差异
2010/10/20 Javascript
基于jquery实现的鼠标滑过按钮改变背景图片
2011/07/15 Javascript
JavaScript异步编程:异步数据收集的具体方法
2013/08/19 Javascript
JS实现三级折叠菜单特效,其它级可自动收缩
2015/08/06 Javascript
js canvas实现擦除动画
2016/07/16 Javascript
原生态js,鼠标按下后,经过了那些单元格的简单实例
2016/08/11 Javascript
iview中Select 选择器多选校验方法
2018/03/15 Javascript
react.js组件实现拖拽复制和可排序的示例代码
2018/08/20 Javascript
在 Vue-CLI 中引入 simple-mock实现简易的 API Mock 接口数据模拟
2018/11/28 Javascript
基于Vue实现的多条件筛选功能的详解(类似京东和淘宝功能)
2019/05/07 Javascript
vue自动添加浏览器兼容前后缀操作
2020/08/13 Javascript
js删除对象中的某一个字段的方法实现
2021/01/11 Javascript
python自动安装pip
2014/04/24 Python
用实例解释Python中的继承和多态的概念
2015/04/27 Python
浅谈Python中copy()方法的使用
2015/05/21 Python
对PyQt5的输入对话框使用(QInputDialog)详解
2019/06/25 Python
python调用其他文件函数或类的示例
2019/07/16 Python
Pytoch之torchvision.transforms图像变换实例
2019/12/30 Python
解决pycharm中导入自己写的.py函数出错问题
2020/02/12 Python
Python爬虫之Selenium库的使用方法
2021/01/03 Python
Bluebella法国官网:英国性感内衣品牌
2019/05/03 全球购物
俄罗斯香水和化妆品网上商店:NOTINO.ru
2019/12/17 全球购物
优良学风班申请材料
2014/02/13 职场文书
2014道德模范事迹材料
2014/02/16 职场文书
学生会宣传部部长竞选演讲稿
2014/04/25 职场文书
2015年学雷锋活动总结
2015/02/06 职场文书
社区五一劳动节活动总结
2015/02/09 职场文书
跑吧孩子观后感
2015/06/10 职场文书
2019大学生预备党员转正思想汇报
2019/06/21 职场文书
SQL Server使用CROSS APPLY与OUTER APPLY实现连接查询
2022/05/25 SQL Server
Android开发手册Chip监听及ChipGroup监听
2022/06/10 Java/Android