Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Scrapy+Selenium爬取动态渲染网站

Scrapy+Selenium爬取动态渲染网站

作者头像
py3study
发布于 2020-11-05 02:22:09
发布于 2020-11-05 02:22:09
1.7K00
代码可运行
举报
文章被收录于专栏:python3python3
运行总次数:0
代码可运行

一、概述

使用情景

在通过scrapy框架进行某些网站数据爬取的时候,往往会碰到页面动态数据加载的情况发生,如果直接使用scrapy对其url发请求,是绝对获取不到那部分动态加载出来的数据值。但是通过观察我们会发现,通过浏览器进行url请求发送则会加载出对应的动态加载出的数据。那么如果我们想要在scrapy也获取动态加载出的数据,则必须使用selenium创建浏览器对象,然后通过该浏览器对象进行请求发送,获取动态加载的数据值

使用流程

1. 重写爬虫文件的__init__()构造方法,在该方法中使用selenium实例化一个浏览器对象

2. 重写爬虫文件的closed(self,spider)方法,在其内部关闭浏览器对象,该方法是在爬虫结束时被调用.

3. 在settings配置文件中开启下载中间件

二、案例演示

这里以房天下为例,爬取楼盘信息,链接如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
https://sh.newhouse.fang.com/house/s/a75-b91/?ctm=1.sh.xf_search.page.1

页面分析

获取信息列表

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//*[@id="newhouse_loupai_list"]/ul/li//div[@class="nlc_details"]

它会获取20条信息

获取名称

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//*[@id="newhouse_loupai_list"]/ul/li//div[@class="nlc_details"]//div[@class="nlcd_name"]/a/text()

结果如下:

获取价格

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//*[@id="newhouse_loupai_list"]/ul/li//div[@class="nlc_details"]//div[@class="nhouse_price"]/span/text()

结果如下:

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

获取区域

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//*[@id="newhouse_loupai_list"]/ul/li//div[@class="relative_message clearfix"]//a/span/text()

结果如下:

 注意:别看它只有17条,因为还有3条,不在国内。比如泰国,老挝等。因此,后续我会它一个默认值:国外

获取地址

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//*[@id="newhouse_loupai_list"]/ul/li//div[@class="relative_message clearfix"]/div/a/text()

结果如下:

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

获取状态

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//*[@id="newhouse_loupai_list"]/ul/li//div[@class="nlc_details"]//span[@class="inSale"]/text()

结果如下:

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

项目代码

通过以上页面分析出我们要的结果只会,就可以正式编写代码了。

创建项目

打开Pycharm,并打开Terminal,执行以下命令

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
scrapy startproject fang
cd fang
scrapy genspider newhouse sh.newhouse.fang.com

在scrapy.cfg同级目录,创建bin.py,用于启动Scrapy项目,内容如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# !/usr/bin/python3
# -*- coding: utf-8 -*-
#在项目根目录下新建:bin.py
from scrapy.cmdline import execute
# 第三个参数是:爬虫程序名
execute(['scrapy', 'crawl', 'newhouse',"--nolog"])

创建好的项目树形目录如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
./
├── bin.py
├── fang
│   ├── __init__.py
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders
│       ├── __init__.py
│       └── newhouse.py
└── scrapy.cfg

修改newhouse.py

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# -*- coding: utf-8 -*-
import scrapy
from scrapy import Request  # 导入模块
import math
import re
from fang.items import FangItem
from selenium.webdriver import ChromeOptions
from selenium.webdriver import Chrome


class NewhouseSpider(scrapy.Spider):
    name = 'newhouse'
    allowed_domains = ['sh.newhouse.fang.com']
    base_url = "https://sh.newhouse.fang.com/house/s/a75-b91/?ctm=1.sh.xf_search.page."
    # start_urls = [base_url+str(1)]

    # 实例化一个浏览器对象
    def __init__(self):
        # 防止网站识别Selenium代码
        options = ChromeOptions()
        options.add_argument("--headless")  # => 为Chrome配置无头模式
        options.add_experimental_option('excludeSwitches', ['enable-automation'])
        options.add_experimental_option('useAutomationExtension', False)

        self.browser = Chrome(options=options)
        self.browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
            "source": """
                            Object.defineProperty(navigator, 'webdriver', {
                              get: () => undefined
                            })
                          """
        })

        super().__init__()

    def start_requests(self):
        print("开始爬虫")
        self.base_url = "https://sh.newhouse.fang.com/house/s/a75-b91/?ctm=1.sh.xf_search.page."
        url = self.base_url + str(1)
        print("url",url)
        # url = "https://news.163.com/"
        response = scrapy.Request(url, callback=self.parse_index)
        yield response

    # 整个爬虫结束后关闭浏览器
    def close(self, spider):
        print("关闭爬虫")
        self.browser.quit()

    # 访问主页的url, 拿到对应板块的response
    def parse_index(self, response):
        print("访问主页")
        # 获取分页
        # 查询条数
        ret_num = response.xpath('//*[@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 = math.ceil(jsfy)
        # print("page_num",page_num)

        for n in range(1, page_num):
            n += 1
            # 下一页url
            url = self.base_url + str(n)
            print("url", url)
            # 访问下一页,有返回时,调用self.parse_details方法
            yield scrapy.Request(url=url, callback=self.parse_details)

    def parse_details(self, response):
        # 获取页面中要抓取的信息在网页中位置节点
        node_list = response.xpath('//*[@id="newhouse_loupai_list"]/ul/li//div[@class="nlc_details"]')

        count = 0
        # 遍历节点,进入详情页,获取其他信息
        for node in node_list:
            count += 1
            try:
                # # 名称
                nlcd_name = node.xpath('.//div[@class="nlcd_name"]/a/text()').extract()

                if nlcd_name:
                    nlcd_name = nlcd_name[0].strip()

                print("nlcd_name", nlcd_name)

                # # # 价格
                price = node.xpath('.//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 = node.xpath('.//div[@class="relative_message clearfix"]//a/span/text()').extract()
                region = ""
                if region_ret:
                    # if len(region) >=2:
                    region_ret = region_ret[0].strip()
                    # 正则匹配中括号的内容
                    p1 = re.compile(r'[\[](.*?)[\]]', re.S)
                    region = re.findall(p1, region_ret)
                    if region:
                        region = region[0]

                # print("region",region)
                # # # # 地址
                address_str = node.xpath('.//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 = re.compile(r'[\[](.*?)[\]]', re.S)  # 最小匹配
                address_ret = re.findall(p1, address_str)

                if address_ret:
                    # 截图地区
                    region = address_ret[0]
                    # 地址拆分
                    add_cut_str = address_str.split()
                    # 截取地址
                    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 = node.xpath('.//span[@class="inSale"]/text()').extract_first()
                # status = node.xpath('.//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)

修改items.py

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class FangItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    nlcd_name = scrapy.Field()
    price = scrapy.Field()
    region = scrapy.Field()
    address = scrapy.Field()
    status = scrapy.Field()

修改pipelines.py

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
import json

class FangPipeline(object):
    def __init__(self):
        # python3保存文件 必须需要'wb' 保存为json格式
        self.f = open("fang_pipline.json", 'wb')

    def process_item(self, item, spider):
        # 读取item中的数据 并换行处理
        content = json.dumps(dict(item), ensure_ascii=False) + ',\n'
        self.f.write(content.encode('utf=8'))

        return item

    def close_spider(self, spider):
        # 关闭文件
        self.f.close()

注意:这里为了方便,保存在一个json文件中。当然,也可以设置保存到数据库中。

修改settings.py,应用pipelines

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ITEM_PIPELINES = {
   'fang.pipelines.FangPipeline': 300,
}

执行bin.py,启动爬虫项目,效果如下:

查看文件fang_pipline.json,内容如下:

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

本文参考链接:

https://www.cnblogs.com/bk9527/p/10504883.html

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/11/04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
scrapy结合selenium进行动态加载页面内容爬取
使用requests进行数据获取的时候一般使用的是respond.text来获取网页源码,然后通过正则表达式提取出需要的内容。
zx钟
2019/07/19
2.5K0
21天打造分布式爬虫-房天下全国658城市房源(十一)
项目:爬取房天下网站全国所有城市的新房和二手房信息 网站url分析 1.获取所有城市url http://www.fang.com/SoufunFamily.htm 例如:http://cq.fang.com/ 2.新房url http://newhouse.sh.fang.com/house/s/ 3.二手房url http://esf.sh.fang.com/ 4.北京新房和二手房url规则不同 http://newhouse.fang.com/house/s
zhang_derek
2018/08/10
9170
python爬虫项目(scrapy-re
python爬虫scrapy项目(二)   爬取目标:房天下全国租房信息网站(起始url:http://zu.fang.com/cities.aspx)   爬取内容:城市;名字;出租方式;价格;户型;面积;地址;交通   反反爬措施:设置随机user-agent、设置请求延时操作、 1、开始创建项目 1 scrapy startproject fang 2、进入fang文件夹,执行启动spider爬虫文件代码,编写爬虫文件。 1 scrapy genspider zufang "zu.fang.com"
py3study
2020/01/19
6980
Scrapy全站抓取-个人博客
想像一下,首先我们需要解析一个网站的首页, 解析出其所有的资源链接(ajax方式或绑定dom事件实现跳转忽略),请求该页面所有的资源链接, 再在资源链接下递归地查找子页的资源链接,最后在我们需要的资源详情页结构化数据并持久化在文件中。这里只是简单的介绍一下全站抓取的大致思路,事实上,其细节的实现,流程的控制是很复杂的。
py3study
2020/11/09
1.2K0
scrapy爬取--腾讯社招的网站
1)使用命令创建爬虫腾讯招聘的职位项目:scrapy startproject tencent
用户2337871
2019/07/19
6780
scrapy爬取--腾讯社招的网站
Python爬虫项目--爬取链家热门城市
本次实战是利用爬虫爬取链家的新房(声明: 内容仅用于学习交流, 请勿用作商业用途)
py3study
2020/01/20
7890
011:运用Scrapy爬取腾讯招聘信息
在tecent_recruit文件夹下找到spiders文件夹, 在此处打开cmd窗口输入命令:scrapy genspider catch_positon tencent.com 创建名为“catch_positon"的爬虫文件
李玺
2021/11/22
7160
011:运用Scrapy爬取腾讯招聘信息
Scrapy入门案例——腾讯招聘(CrawlSpider升级)
需求和上次一样,只是职位信息和详情内容分开保存到不同的文件,并且获取下一页和详情页的链接方式有改动。
100000860378
2018/09/13
8060
Scrapy入门案例——腾讯招聘(CrawlSpider升级)
Scrapy入门案例——腾讯招聘
爬取腾讯招聘的职位信息,并保存为json文件。 获得现有的3571条职位信息(职位名称、职位类别、人数、地点发布时间、详情页的链接),并获得详情页的内容。
100000860378
2018/09/13
6510
Scrapy入门案例——腾讯招聘
Python爬虫之scrapy框架学习
scrapy安装步骤 pip install wheel 下载twisted : 地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted (选择对应的版本) 安装twisted : pip install aiohttp-3.8.1-cp38-cp38-win_amd64.whl pip install pywin32 pip install scrapy 测试终端输入: scrapy 创建工程 终端输入: scrapy startproject fi
shaoshaossm
2022/12/26
7300
一个小时多点,完成scrapy爬取官方网站新房的数据
在前几天,接到一个大学生的作业的爬虫单子,要求采用scrapy爬取链家官方网站新房的数据(3-5页即可,太多可能被封禁ip),网址:https://bj.fang.lianjia.com/loupan/,将楼盘名称、价格、平米数等(可以拓展)数据保存到一个json文件中。
润森
2020/05/04
1.4K0
基于Scrapy框架爬取厦门房价
本文的运行环境是Win10,IDE是Pycharm,Python版本是3.6。 请先保证自己安装好Pycharm和Scrapy。
潇洒坤
2018/09/10
1.3K0
基于Scrapy框架爬取厦门房价
Scrapy框架之爬取城市天气预报
1.项目初始化2.提取数据 2.1 原理分析 2.2 数据抽取 2.3 自定义spider3.存储数据 3.1 修改settings.py 3.2 数据存储4.结果展示5.作者的话
公众号guangcity
2019/09/20
1.8K1
Scrapy框架之爬取城市天气预报
python scrapy爬虫练习(1) 爬取豆瓣电影top250信息
文章目录 一、分析网页 目标URL:https://movie.douban.com/top250?start=0&filter= 每一页有25条电影信息,总共10页。检查网页可以发现,每条电影的详细
叶庭云
2020/09/17
5.2K0
python  scrapy爬虫练习(1)   爬取豆瓣电影top250信息
Scrapy爬取二手房信息+可视化数据分析
本篇介绍一个scrapy的实战爬虫项目,并对爬取信息进行简单的数据分析。目标是北京二手房信息,下面开始分析。
Python数据科学
2018/08/06
1.1K0
Scrapy爬取二手房信息+可视化数据分析
Python网络爬虫(七)- 深度爬虫CrawlSpider1.深度爬虫CrawlSpider2.链接提取:LinkExtractor3.爬取规则:rules4.如何在pycharm中直接运行爬虫5.
目录: Python网络爬虫(一)- 入门基础 Python网络爬虫(二)- urllib爬虫案例 Python网络爬虫(三)- 爬虫进阶 Python网络爬虫(四)- XPath Python网络爬虫(五)- Requests和Beautiful Soup Python网络爬虫(六)- Scrapy框架 Python网络爬虫(七)- 深度爬虫CrawlSpider Python网络爬虫(八) - 利用有道词典实现一个简单翻译程序 深度爬虫之前推荐一个简单实用的库fake-useragent,可以伪装
Python攻城狮
2018/08/23
1.9K0
Python网络爬虫(七)- 深度爬虫CrawlSpider1.深度爬虫CrawlSpider2.链接提取:LinkExtractor3.爬取规则:rules4.如何在pycharm中直接运行爬虫5.
初识Scrapy框架+爬虫实战(7)-爬取链家网100页租房信息
Item 是保存爬取到的数据的容器。比如我下面将要爬取的链家网租房信息的地点、平米数、价格,我会在item.py文件中定义相应的字段。
秦子帅
2019/08/17
1.3K0
初识Scrapy框架+爬虫实战(7)-爬取链家网100页租房信息
python爬虫–scrapy(再探)
— 图片:xpath解析出图片src的属性值。单独的对图片地址发起请求获取图片二进制类型的数据。
全栈程序员站长
2021/04/21
6760
python爬虫–scrapy(再探)
【scrapy】scrapy爬取数据指南
scrapy是爬虫界常用的基于Python爬虫框架,但是网上找了很多这类的文章,发现有多处错误,故为了让刚想尝试爬虫的蜘蛛们少走点坑,故把最新的方法奉上。 在此之前,请先更新你的pip版本,并安装scrapy , pymysql。
前端修罗场
2023/10/07
5850
【scrapy】scrapy爬取数据指南
scrapy全站爬取
需求:爬取站长素材的高清图片的爬取https://sc.chinaz.com/tupian/
用户8447427
2022/08/18
8390
scrapy全站爬取
推荐阅读
相关推荐
scrapy结合selenium进行动态加载页面内容爬取
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验