在没有系统学习框架进行爬虫的时候,已经可以使用selenium对动态渲染的网页和Ajax加载数据的网页进行爬取,但代码的整体逻辑在于自己对于方法的认识编写和使用,没有很强的逻辑框架性,在自学Scrapy框架的时候也学到对于Selenium的对接,最近进行了学习,现在和大家分享,有什么不足或错误的地方请评论或私信哟😁
使用selenium对网页抓取的原理在于,使用selenium模拟登陆浏览器进行抓取,不需要关心页面后台发生的请求,也不需要分析页面渲染过程,只需要关注页面最终结果即可,在进行网页跳转的时候,也只需要关心URL的变化规律,从而来构造请求列表来重复进行请求,也不需要关心如何去构造请求头。
Scrapy对接Selenium
- 1. 新建项目
- 2. 创建 Spider
- 3. 网页的分析和自己爬取数据的确定
- 4. 定义Item
- 5. 构造 Request 请求列表
- 6. 对接 Selenium (说明在哪里进行对接为什么在这里)
-
- 6.1 启动自己所编写的 Downloader Middlewares
- 7. 对页面进行解析
- 8. 将数据存入数据库当中(Item Pipeline)
-
- 8.1 定义自己的 Item Pipeline
- 8.2 启动Item Pipeline
- 9. 运行
- 10. 运行结果
1. 新建项目
scrapy startproject scrapyselenium(项目名)
2. 创建 Spider
直接用Pycharm打开上一步所创建的项目,在最下面的Terminal处执行该命令:
scrapy genspider xiaozhu www.xiaozhu.com
3. 网页的分析和自己爬取数据的确定
目标网页URL(第一页):
url = 'https://cq.xiaozhu.com/search-duanzufang-p0-0/'
这个网页不是小猪短租的官网,这是在选择了地点(我选地点是重庆)后出现的页面的URL,因为我是为了去熟悉使用并了解Scrapy对接selenium,所以就直接偷懒选择了固定地点后的页面去进行分析。
由于是使用selenium进行可见可爬,所以不需要进行一系列的关于Request和Response请求的分析,转向寻找URL变化的规律,从而来构建Request的请求列表:
https://cq.xiaozhu.com/search-duanzufang-p0-0/
https://cq.xiaozhu.com/search-duanzufang-p1-0/
https://cq.xiaozhu.com/search-duanzufang-p2-0/
可以发现它的变化仅仅在于p0,p1的变化,用来控页数,接着我们就来看看自己所要的信息在哪,这里不建议直接f12去查看源代码,这个是辅助查询,主要代码依据是在服务器返回的请求响应中去查看源代码,源代码很可能在第一个响应中:
并发现每一个房子的相关信息都存在 li 标签,class为current的标签当中,然后我就开始下一步的分析。
4. 定义Item
为要爬取的数据进行字段的定义。
import scrapy
from scrapy import Field
class HouseItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
house_name = Field()
#location = Field()
house_price = Field()
house_href = Field()
house_size = Field()
5. 构造 Request 请求列表
根据URL连接变化的规律来在 Spider中进行构造:
#这里ragne函数代表了页数的变化,为了测试,我这里只定义了一页的数据
def start_requests(self):
for i in range(1):
i = str(i)
url = 'https://cq.xiaozhu.com/search-duanzufang-p' + i + '-0/'
yield Request(url=url,callback=self.parse)
6. 对接 Selenium (说明在哪里进行对接为什么在这里)
在构造完请求列表后,就要对这些请求进行抓取,从Scrapy整体框架和数据流的流向进行分析,当引擎从Scheduler中调度出请求后,请求将会被发往Downloader进行下载,在被下载之前会经过 Downloader Middleware下载器中间件进行请求的处理,我们变可以在这里对请求进行拦截,处理这个请求,使用Selenium对请求进行处理,最后返回HttpResponse请求,直接跳过下载器,直接交给Spider进行处理。
要先对这个请求进行拦截,我们需要在 middleware.py 中进行代码的编写,定义自己的中间类并进行启动,因为是处理到达下载器之前的Request请求,所以需要重写 process_request() 方法。
对于Scrapy项目运行数据流总览 AND 几个重要的组件、中间件分析,我的这篇博文已经给出:
https://blog.csdn.net/zc666ying/article/details/106601578
# 因为目的是测试并了解对接Selenium,并未做出任何模拟的点击,简单明了直接获取网页源码并返回
class SeleniumMiddleware(object):
def process_request(self,request,spider):
driver = webdriver.Chrome()
#driver.maximize_window()
driver.get(request.url)
time.sleep(3)
text = driver.page_source
driver.quit()
# https://doc.scrapy.org/en/latest/topics/request-response.html
# 查看 HtmlResponse 对象结构
return HtmlResponse(url=request.url,encoding='utf-8',body=text,request=request)
6.1 启动自己所编写的 Downloader Middlewares
在 settings.py 中进行设置:
DOWNLOADER_MIDDLEWARES = {
'scrapyselenium.middlewares.SeleniumMiddleware':543,
}
7. 对页面进行解析
由于上面说到所返回的Response对象会直接给Spider,所以直接编写解析函数 parse():
def parse(self, response):
house_name = response.xpath('//img[@class="lodgeunitpic"]/@title').extract()
house_price = response.xpath('//span[@class="result_price"]//i/text()').extract()
house_size = response.xpath('//em[@class="hiddenTxt"]/text()').extract()
house_href = response.xpath('//a[contains(@target,"_blank") and @class="resule_img_a"]/@href').extract()
for i in range(len(house_name)):
item = HouseItem(
house_name = house_name[i],
house_price = house_price[i],
house_size = house_size[i],
house_href = house_href[i]
)
yield item
8. 将数据存入数据库当中(Item Pipeline)
8.1 定义自己的 Item Pipeline
import pymysql
class PymysqlPipeline(object):
#连接数据库
def __init__(self):
self.connect = pymysql.connect(
host = 'localhost',
database = 'xiaozhu_house',
user = 'root',
password = '123456',
charset = 'utf8',
port = 3306
)
# 创建游标对象
self.cursor = self.connect.cursor()
# 此方法是必须要实现的方法,被定义的 Item Pipeline 会默认调用这个方法对 Item 进行处理
def process_item(self,item,spider):
cursor = self.cursor
sql = 'insert into house_information(house_name,house_price,house_size,house_href) values (%s,%s,%s,%s)'
cursor.execute(sql,(
item['house_name'],item['house_price'],item['house_size'],item['house_href']
))
# 提交数据库事务
self.connect.commit()
return item
8.2 启动Item Pipeline
在 settings.py 中进行设置:
ITEM_PIPELINES = {
'scrapyselenium.pipelines.PymysqlPipeline':300
}
9. 运行
scrapy crawl xiaozhu