Scrapy+Selenium爬取动态渲染网站

Scrapy+Selenium爬取动态渲染网站

2023年6月29日发(作者:)

Scrapy+Selenium爬取动态渲染⽹站⼀、概述使⽤情景在通过scrapy框架进⾏某些⽹站数据爬取的时候,往往会碰到页⾯动态数据加载的情况发⽣,如果直接使⽤scrapy对其url发请求,是绝对获取不到那部分动态加载出来的数据值。但是通过观察我们会发现,通过浏览器进⾏url请求发送则会加载出对应的动态加载出的数据。那么如果我们想要在scrapy也获取动态加载出的数据,则必须使⽤selenium创建浏览器对象,然后通过该浏览器对象进⾏请求发送,获取动态加载的数据值使⽤流程1. 重写爬⾍⽂件的__init__()构造⽅法,在该⽅法中使⽤selenium实例化⼀个浏览器对象2. 重写爬⾍⽂件的closed(self,spider)⽅法,在其内部关闭浏览器对象,该⽅法是在爬⾍结束时被调⽤.3. 在settings配置⽂件中开启下载中间件

⼆、案例演⽰这⾥以房天下为例,爬取楼盘信息,链接如下:/house/s/a75-b91/?ctm=_.1

页⾯分析获取信息列表//*[@id="newhouse_loupai_list"]/ul/li//div[@class="nlc_details"]它会获取20条信息

获取名称//*[@id="newhouse_loupai_list"]/ul/li//div[@class="nlc_details"]//div[@class="nlcd_name"]/a/text()结果如下:

获取价格//*[@id="newhouse_loupai_list"]/ul/li//div[@class="nlc_details"]//div[@class="nhouse_price"]/span/text()结果如下:

注意:别看它只有18条,因为还有2条,价格没有公布,所以获取不到。因此,后续我会它⼀个默认值:价格待定

获取区域//*[@id="newhouse_loupai_list"]/ul/li//div[@class="relative_message clearfix"]//a/span/text()结果如下: 注意:别看它只有17条,因为还有3条,不在国内。⽐如泰国,⽼挝等。因此,后续我会它⼀个默认值:国外

获取地址//*[@id="newhouse_loupai_list"]/ul/li//div[@class="relative_message clearfix"]/div/a/text()结果如下:

注意:多了17条,为什么呢?因此地址有些含有⼤段的空⾏,有些地址还包含了区域信息。因此,后续我会做⼀下处理,去除多余的换⾏符,通过正则匹配出地址信息。

获取状态//*[@id="newhouse_loupai_list"]/ul/li//div[@class="nlc_details"]//span[@class="inSale"]/text()

结果如下:

注意:少了4条,那是因为它的状态是待售。因此,后续我会做⼀下处理,没有匹配的,给定默认值。

项⽬代码通过以上页⾯分析出我们要的结果只会,就可以正式编写代码了。创建项⽬打开Pycharm,并打开Terminal,执⾏以下命令scrapy startproject fangcd fangscrapy genspider newhouse

在同级⽬录,创建,⽤于启动Scrapy项⽬,内容如下:# !/usr/bin/python3# -*- coding: utf-8 -*-#在项⽬根⽬录下新建: e import execute# 第三个参数是:爬⾍程序名execute(['scrapy', 'crawl', 'newhouse',"--nolog"])

创建好的项⽬树形⽬录如下:./├── ├── fang│ ├── __init__.py│ ├── │ ├── │ ├── │ ├── │ └── spiders│ ├── __init__.py│ └── └──

修改# -*- coding: utf-8 -*-import scrapyfrom scrapy import Request # 导⼊模块import mathimport refrom import FangItemfrom ver import ChromeOptionsfrom ver import Chromeclass NewhouseSpider(): name = 'newhouse' allowed_domains = [''] base_url = "/house/s/a75-b91/?ctm=_." # start_urls = [base_url+str(1)] # 实例化⼀个浏览器对象 def __init__(self): # 防⽌⽹站识别Selenium代码 options = ChromeOptions() _argument("--headless") # => 为Chrome配置⽆头模式 _experimental_option('excludeSwitches', ['enable-automation']) _experimental_option('useAutomationExtension', False) r = Chrome(options=options) e_cdp_cmd("iptToEvaluateOnNewDocument", { "source": """ Property(navigator, 'webdriver', { get: () => undefined }) """ }) super().__init__() def start_requests(self): print("开始爬⾍") _url = "/house/s/a75-b91/?ctm=_." url = _url + str(1) print("url",url) # url = "/" response = t(url, callback=_index) yield response # 整个爬⾍结束后关闭浏览器 def close(self, spider): print("关闭爬⾍") () # 访问主页的url, 拿到对应板块的response def parse_index(self, response): print("访问主页") # 获取分页 # 查询条数 ret_num = ('//*[@id="sjina_C01_47"]/ul/li[1]/b/text()').extract_first() # print("ret_num", ret_num, type(ret_num)) # 计算分页,每⼀页20条 jsfy = int(ret_num) / 20 # 向上取整 page_num = (jsfy) # print("page_num",page_num) for n in range(1, page_num): n += 1 # 下⼀页url url = _url + str(n) print("url", url) # 访问下⼀页,有返回时,调⽤_details⽅法 yield t(url=url, callback=_details) def parse_details(self, response): # 获取页⾯中要抓取的信息在⽹页中位置节点 node_list = ('//*[@id="newhouse_loupai_list"]/ul/li//div[@class="nlc_details"]') count = 0 # 遍历节点,进⼊详情页,获取其他信息 for node in node_list: count += 1 try: # # 名称 nlcd_name = ('.//div[@class="nlcd_name"]/a/text()').extract() if nlcd_name: nlcd_name = nlcd_name[0].strip() print("nlcd_name", nlcd_name) # # # 价格 price = ('.//div[@class="nhouse_price"]/span/text()').extract() # print("原price",price,type(price)) if price: price = price[0].strip() if not price: price = "价格待定" print("price", price) # 区域 region_ret = ('.//div[@class="relative_message clearfix"]//a/span/text()').extract() region = "" if region_ret: # if len(region) >=2: region_ret = region_ret[0].strip() # 正则匹配中括号的内容 p1 = e(r'[[](.*?)[]]', re.S) region = l(p1, region_ret) if region: region = region[0] # print("region",region) # # # # 地址 address_str = ('.//div[@class="relative_message clearfix"]/div/a/text()').extract() address = "" # 判断匹配结果,截取地址信息 if address_str: if len(address_str) >= 2: address_str = address_str[1].strip() else: address_str = address_str[0].strip() # print("address_str", address_str) # 判断地址中,是否含有区域信息,⽐如[松江] p1 = e(r'[[](.*?)[]]', re.S) # 最⼩匹配 address_ret = l(p1, address_str) if address_ret: # 截图地区 region = address_ret[0] # 地址拆分 add_cut_str = address_() # 截取地址 if add_cut_str: address = add_cut_str[1] else: address = address_str # 为空时,表⽰在国外 if not region_ret: region = "国外" print("region", region) print("address", address) # # # 状态 status = ('.//span[@class="inSale"]/text()').extract_first() # status = ('.//div[@class="fangyuan pr"]/span/text()').extract_first() if not status: status = "待售" print("status", status) # item item = FangItem() item['nlcd_name'] = nlcd_name item['price'] = price item['region'] = region item['address'] = address item['status'] = status yield item except Exception as e: print(e) print("本次爬取数据: %s条" % count)View Code

修改# -*- coding: utf-8 -*-# Define here the models for your scraped items## See documentation in:# /en/latest/topics/port scrapyclass FangItem(): # define the fields for your item here like: # name = () nlcd_name = () price = () region = () address = () status = ()View Code

修改# -*- coding: utf-8 -*-# Define your item pipelines here## Don't forget to add your pipeline to the ITEM_PIPELINES setting# See: /en/latest/topics/port jsonclass FangPipeline(object): def __init__(self): # python3保存⽂件 必须需要'wb' 保存为json格式 self.f = open("fang_", 'wb') def process_item(self, item, spider): # 读取item中的数据 并换⾏处理 content = (dict(item), ensure_ascii=False) + ',n' (('utf=8')) return item def close_spider(self, spider): # 关闭⽂件 ()View Code注意:这⾥为了⽅便,保存在⼀个json⽂件中。当然,也可以设置保存到数据库中。

修改,应⽤pipelinesITEM_PIPELINES = { 'peline': 300,}

执⾏,启动爬⾍项⽬,效果如下:

查看⽂件fang_,内容如下:

注意:本次访问的页⾯,只有6页,每页20条结果。因此可以获取到120条信息。

本⽂参考链接:

发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1687985976a63975.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信