13-scrapy中selenium的应用
一. 引入
在通过scrapy框架进行某些网站数据爬取的时候,往往会碰到页面动态数据加载的情况发生,如果直接使用scrapy对其url发请求,是绝对获取不到那部分动态加载出来的数据值。但是通过观察我们会发现,通过浏览器进行url请求发送则会加载出对应的动态加载出的数据。那么如果我们想要在scrapy也获取动态加载出的数据,则必须使用selenium创建浏览器对象,然后通过该浏览器对象进行请求发送,获取动态加载的数据值。
二. 今日详情
1.案例分析:
(1).需求: 爬取网易新闻的国内板块下的新闻数据
(2).需求分析: 当点击国内超链接进入国内对应的页面时, 会发现当前页面展示的新闻数据是被动态加载出来的, 如果直接通过程序对url进行请求, 是获取不到动态加载出的新闻数据的, 则就需要我们使用selenium实例化一个浏览器对象, 在该对象中进行url请求, 获取动态加载的新闻数据
2. selenium在scrapy中使用的原理分析:
当引擎将国内板块url对应的请求提交给下载器后,下载器进行网页数据的下载,然后将下载到的页面数据,封装到response中,提交给引擎,引擎将response在转交给Spiders。Spiders接受到的response对象中存储的页面数据里是没有动态加载的新闻数据的。要想获取动态加载的新闻数据,则需要在下载中间件中对下载器提交给引擎的response响应对象进行拦截,切对其内部存储的页面数据进行篡改,修改成携带了动态加载出的新闻数据,然后将被篡改的response对象最终交给Spiders进行解析操作。
3. selenium在scrapy中的使用流程:
- 重写爬虫文件的构造方法,在该方法中使用selenium实例化一个浏览器对象(因为浏览器对象只需要被实例化一次)
- 重写爬虫文件的closed(self,spider)方法,在其内部关闭浏览器对象。该方法是在爬虫结束时被调用
- 重写下载中间件的process_response方法,让该方法对响应对象进行拦截,并篡改response中存储的页面数据
- 在配置文件中开启下载中间件
4. 代码展示:
爬虫文件代码:
# -*- coding: utf-8 -*-
import scrapy
from Wangyixinwen.items import WangyixinwenItem
from selenium import webdriver class WangyiSpider(scrapy.Spider):
name = 'wangyi'
# allowed_domains = ['www.xxx.com']
#自动发送请求的 去设置里将user-agent以及robots协议设置好
start_urls = ['https://news.163.com/']
""""
我们的第一次请求对象就是start_urls开始,我们还需要对UA伪装同时还有IP代理等,可以在下载中间件的process_request中设置UA伪装
process_exception中设置代理ip(等到自己ip出问题了就用代理ip)。等到响应对象缺失就可以在process_response中拦截。
"""
bro = webdriver.Chrome("./chromedriver.exe")
urls = []
def parse(self, response):
#从响应对象中获取到全部目标
target_list = response.xpath('//*[@id="js_festival_wrap"]/div[3]/div[2]/div[2]/div[2]/div/ul/li')
#遍历目标得到具体的url
for index in [3,6,7,8]:
target = target_list[index]
#得到目标的url 并且取出url
target_url = target.xpath('./a/@href').extract_first()
self.urls.append(target_url)
#对目标url发起请求
yield scrapy.Request(url=target_url,callback=self.parse_target)
def parse_target(self,response):
#将第二次请求的响应对象开始解析,分析由于还未编写代码就知道这次是含有动态加载数据,因此这次
#分析可以用到selenium一起解析数据,下面解析出新闻标题以及具体的详情页的url(响应的数据缺失,因此我们需要去下载中间件设置)
detail_list = response.xpath('/html/body/div[1]/div[3]/div[4]/div[1]/div/div/ul/li/div/div')
for detail in detail_list:
title = detail.xpath('./div/div[1]/h3/a/text()').extract_first()
detail_url = detail.xpath('./div/div[1]/h3/a/@href').extract_first()
#实例化item对象,封装数据
item = WangyixinwenItem()
item["title"] = title
yield scrapy.Request(url=detail_url,callback=self.parse_detail,meta={"item":item})
def parse_detail(self,response):
item = response.meta['item']
content = response.xpath('//*[@id="endText"]/p/text()').extract()
#将内容转换为字符串对象
content = "".join(content)
item["content"] = content
#提交数据
yield item
def close(self,spider):
# 爬虫结束,浏览器也关闭
print("爬虫结束!!!")
self.bro.quit()
中间件文件拦截代码展示:
# -*- coding: utf-8 -*- # Define here the models for your spider middleware
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/spider-middleware.html from scrapy import signals
from scrapy.http import HtmlResponse
import random
from time import sleep class WangyixinwenDownloaderMiddleware(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. def process_request(self, request, spider): return None def process_response(self, request, response, spider):
#刚才响应体缺失,因此从这里我们应该重新返回新的响应体
#这里要用到爬虫程序中的urls,判断url是否在里面,在urls里面的就会出现响应缺失,
# 、因此需要返回新的响应体
if request.url in spider.urls:
#响应缺失是因为是动态加载数据,因此我们配合selenium使用
#在这里实例化selenium的话会被实例化多次,然而selenium只需要实例化一次,
#这个时候我们可以将selenium放在实例化一次的爬虫程序开始的时候,实例化完成引入
sleep(2)
bro = spider.bro.get(url=request.url)#浏览器中发送请求
sleep(1)
spider.bro.execute_script("window.scrollTo(0,document.body.scrollHeight)")
sleep(1.5)
spider.bro.execute_script("window.scrollTo(0,document.body.scrollHeight)")
sleep(0.7)
spider.bro.execute_script("window.scrollTo(0,document.body.scrollHeight)")
sleep(1)
spider.bro.execute_script("window.scrollTo(0,document.body.scrollHeight)")
#发送到请求我们需要获取浏览器当前页面的源码数据 获取数据之前需要翻滚页面
page_text = spider.bro.page_source
#改动返回响应对象 scrapy提供了一个库url=spider.bro.current_url, body=page_text, encoding='utf-8', request=request
new_response = HtmlResponse(url=request.url,body=page_text,encoding="utf-8",request=request)
return new_response
else:
return response
#提交完新的响应体之后,去设置将下载中间件打开 def process_exception(self, request, exception, spider):
pass
备注:仔细看代码注释,能够迅速唤醒记忆,更快开发。
13-scrapy中selenium的应用的更多相关文章
- 15.scrapy中selenium的应用
引入 在通过scrapy框架进行某些网站数据爬取的时候,往往会碰到页面动态数据加载的情况发生,如果直接使用scrapy对其url发请求,是绝对获取不到那部分动态加载出来的数据值.但是通过观察我们会发现 ...
- scrapy中selenium的应用
引入 在通过scrapy框架进行某些网站数据爬取的时候,往往会碰到页面动态数据加载的情况发生,如果直接使用scrapy对其url发请求,是绝对获取不到那部分动态加载出来的数据值.但是通过观察我们会发现 ...
- scrapy中 selenium(中间件) + 语言处理 +mysql
在通过scrapy框架进行某些网站数据爬取的时候,往往会碰到页面动态数据加载的情况发生,如果直接使用scrapy对其url发请求,是绝对获取不到那部分动态加载出来的数据值.但是通过观察我们会发现,通过 ...
- 15,scrapy中selenium的应用
引入 在通过scrapy框架进行某些网站数据爬取的时候,往往会碰到页面动态数据加载的情况发生如果直接用scrapy对其url发请求,是获取不到那部分动态加载出来的数据值,但是通过观察会发现,通过浏览器 ...
- 14 Scrapy中selenium的应用
在通过scrapy框架进行某些网站数据爬取的时候,往往会碰到页面动态数据加载的情况发生,如果直接使用scrapy对其url发请求,是绝对获取不到那部分动态加载出来的数据值.但是通过观察我们会发现,通过 ...
- selenium在scrapy中的使用、UA池、IP池的构建
selenium在scrapy中的使用流程 重写爬虫文件的构造方法__init__,在该方法中使用selenium实例化一个浏览器对象(因为浏览器对象只需要被实例化一次). 重写爬虫文件的closed ...
- Scrapy中集成selenium
面对众多动态网站比如说淘宝等,一般情况下用selenium最好 那么如何集成selenium到scrapy中呢? 因为每一次request的请求都要经过中间件,所以写在中间件中最为合适 from se ...
- 在Scrapy中使用selenium
在scrapy中使用selenium 在scrapy中需要获取动态加载的数据的时候,可以在下载中间件中使用selenium 编码步骤: 在爬虫文件中导入webdrvier类 在爬虫文件的爬虫类的构造方 ...
- selenium在scrapy中的应用
引入 在通过scrapy框架进行某些网站数据爬取的时候,往往会碰到页面动态数据加载的情况发生,如果直接使用scrapy对其url发请求,是绝对获取不到那部分动态加载出来的数据值.但是通过观察我们会发现 ...
- 第三百五十一节,Python分布式爬虫打造搜索引擎Scrapy精讲—将selenium操作谷歌浏览器集成到scrapy中
第三百五十一节,Python分布式爬虫打造搜索引擎Scrapy精讲—将selenium操作谷歌浏览器集成到scrapy中 1.爬虫文件 dispatcher.connect()信号分发器,第一个参数信 ...
随机推荐
- 菜鸟刷面试题(一、Java基础篇)
目录: JDK 和 JRE 有什么区别? == 和 equals 的区别是什么? 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗? final 在 java 中有什 ...
- 12. Go 语言文件处理
Go 语言文件处理 本章我们将带领大家深入了解一下 Go语言中的文件处理,重点在于文件而非目录或者通用的文件系统,特别是如何读写标准格式(如 XML 和 JSON 格式)的文件以及自定义的纯文本和二进 ...
- Linux下dos2unix命令将windows文件编码格式dos转换成Unix格式
问题描述: 在Windows系统下面使用文本编辑器notepad后传到Linux系统下的话 Linux下处理和执行一般都存在一些问题,我们可以通过命令查看文件是否是dos格式的, 如果有如图所示的M标 ...
- java并发编程-12个原子类
背景 多线程更新变量的值,可能得不到预期的值,当然增加syncronized关键字可以解决线程并发的问题. 这里提供另外一种解决问题的方案,即位于 java.util.concurrent.atomi ...
- redis 事务(悲观锁和乐观锁)
MULTI 开启事务,后续的命令会被加入到同一个事务中 事务中的操作会发送给客服端,但是不会立即执行,而是将操作放到了该事务对应的一个队列中,服务端返回QUEQUD EXEC 执行EXEC后,事务中的 ...
- Java 面试宝典!并发编程 71 道题及答案全送上!
金九银十跳槽季已经开始,作为 Java 开发者你开始刷面试题了吗?别急,我整理了71道并发相关的面试题,看这一文就够了! 1.在java中守护线程和本地线程区别? java中的线程分为两种:守护线程( ...
- PHP实现支付宝登录
1.支付宝路由拼接 public function dev() { $http = 'https://openauth.alipaydev.com/oauth2/publicAppAuthorize. ...
- javaWeb核心技术第五篇之jQuery
- 概述 - jQuery是一个优秀的javascript框架(js类库),兼容css3和各大浏览器,提供dom,events,animate,ajax等简易的操作.并且jQuery有非常丰富的插件, ...
- 文本分类Pipeline
- CSS学习笔记-动画模块
动画模块: 1.过渡和动画之间的异同 1.1不同点 (1)过渡必须人为触发才能执行 (2)动画不需要人为触发就可以执行 1 ...