Scrapy框架(6):将Selenium集成至Scrapy中

一、总体功能概述

在日常学习过程中发现并非所有网页都能通过Scrapy抓取,原因在于JavaScript动态渲染,使用Selenium模拟浏览器爬取,无需关心后台请求,也不需要分析渲染过程,只要网页最终页面上能看到的内容均可抓取。本次实验所用的网页是链家网,利用Scrapy+Selenium,抓取数据的内容为昆明二手房房源信息,包括房源所在小区名称、地区、朝向、面积、结构、售价以及单位售价。将数据存入MySQL数据库,分组统计不同地区二手房数量,并筛选出总数大于一百的地区,利用pyecharts绘制柱状图实现数据可视化。最终以此为依据分析不同地区的经济发展水平、人口流动量等信息。

二、具体实施步骤

1、安装chromdriver,并配置环境变量

(1)查看chrome版本(chrome://version/)
在这里插入图片描述
(2)安装对应版本的驱动器chromdriver,选择对应的版本以及对应操作系统(64位操作系统是兼容32位的)
在这里插入图片描述
(3)配置环境变量
在这里插入图片描述
(4)安装Selenium,测试chromdriver
在这里插入图片描述
在这里插入图片描述

2、构建基本框架

创建虚拟环境,进入虚拟环境安装需要的库,创建工程并进入工程创建爬虫(以上操作均在黑窗口完成),新建main.py作为入口文件。
scrapy框架(2):入口文件

3、将Selenium集成到Scrapy中(下载中间件middlewares.py)

每发送一个请求都会走下载中间件,为了把Selenium集成到Scrapy中,需要在这个部分做一些拦截,使Selenium根据对应的url访问网页,并将结果响应回框架(在爬虫逻辑解析数据),不再使用下载器下载。
在这里插入图片描述

4、打开、关闭浏览器(爬虫逻辑)

打开浏览器很容易,但是在什么时候关闭浏览器?于是引入了Signals信号,产生信号通知事情的发生,可以通过捕捉相应的信号来做对应的操作。
Scrapy官方文档Signals页

在这里插入图片描述

5、解析数据(爬虫逻辑)

Parse为解析函数,利用CSS选择器筛选目标数据,即房源所在小区名称、地区、朝向、面积、结构、售价以及单位售价,利用zip将每一条房源的信息打包为一个元组,通过引擎传入pipelines.py进行数据处理等操作。解析函数的目的除了获取目标数据之外,还需要获取下一页的url。了解Scrapy的原理每一次解析的response都有对应的url,在此基础上通过字符串的拼接,获得新的url,并将其传回爬虫逻辑。
scrapy框架(3):CSS选择器解析数据

在这里插入图片描述

6、存入数据库(pipelines.py)

使用pymysql,连接MySQL和pycharm。pymysql的使用(pycharm与mysql的连接)
在这里插入图片描述
在这里插入图片描述

7、查找用于绘制柱状图的数据

按地区分组筛选二手房总数大于一百的数据。
在这里插入图片描述

8、pyecharts绘图

Scrapy框架(5):翻页操作、数据库存储以及简单的数据可视化
在这里插入图片描述
在这里插入图片描述

三、具体代码

1、入口文件

import os  # 用os模块定位到当前的目录
import sys
from scrapy.cmdline import execute
sys.path.append(os.path.dirname(os.path.abspath(__file__)))   # __file__为当前文件
execute(["scrapy","crawl","LianjiaSpider"])

2、爬虫逻辑

from urllib.parse import urljoin
import scrapy
from scrapy import signals
from selenium import webdriver

from FinalProject.items import FinalprojectItem

class LianjiaspiderSpider(scrapy.Spider):
    name = 'LianjiaSpider'
    allowed_domains = ['lianjia.com']
    start_urls = ['https://km.lianjia.com/ershoufang/pg1/']


    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = super(LianjiaspiderSpider, cls).from_crawler(crawler, *args, **kwargs)
        spider.chrome=webdriver.Chrome()
        crawler.signals.connect(spider.spider_closed, signal=signals.spider_closed)
        return spider

    def spider_closed(self, spider):
        spider.chrome.quit()
        print("爬虫结束!!!!!!")

    def parse(self, response):
        name=response.css("div.positionInfo a:nth-child(2)::text").extract()   # 小区名称
        price = response.css("div.totalPrice span::text").extract()  # 每套房的售价
        message = response.css("div.houseInfo::text").extract()  # 每套房的相关信息
        position=response.css("div.positionInfo a:nth-child(3)::text").extract()  # 区名
        uniprice=response.css("div.unitPrice span::text").extract()  # 每平米单价

        room_nums=[]  # 房子是几室几厅
        area=[]  # 房子的面积
        ori=[]  # 房子的朝向
        for num in message:
            room_nums.append(num.split("|")[0])
            area.append(num.split("|")[1])
            ori.append(num.split("|")[2])

        Infos=zip(name,price,room_nums,area,ori,position,uniprice)
        finalprojectItem=FinalprojectItem()
        for Info in Infos:
            finalprojectItem["name"] = Info[0]
            finalprojectItem["price"] = Info[1]
            finalprojectItem["room_nums"] = Info[2]
            finalprojectItem["area"] = Info[3]
            finalprojectItem["ori"] = Info[4]
            finalprojectItem["position"]=Info[5]
            finalprojectItem["uniprice"] = Info[6]
            yield finalprojectItem

        next=response.url
        next_page=int(next.strip('/').split('pg')[1]) + 1
        url=urljoin(response.url,"/ershoufang/pg"+str(next_page))
        if next_page==101:
            return 0
        yield scrapy.Request(url, callback=self.parse)  # 回调和调用的区别 parse()和parse

3、items.py

import scrapy


class FinalprojectItem(scrapy.Item):
    name = scrapy.Field()
    price = scrapy.Field()
    position = scrapy.Field()
    uniprice = scrapy.Field()
    room_nums =scrapy.Field()
    area = scrapy.Field()
    ori = scrapy.Field()
    pass

4、下载中间件

from scrapy.http import HtmlResponse

class SeleniumMiddleware:

    def process_request(self, request, spider):
        url = request.url
        # self.chrome.get(url)
        # html=self.chrome.page_source
        # print(html)
        spider.chrome.get(url)
        html=spider.chrome.page_source
        return HtmlResponse(url=url,body=html,request=request,encoding="utf-8")

5、pipelins.py

import pymysql

class FinalprojectPipeline:
    def __init__(self):  # 连接到数据库
        self.conn = pymysql.connect(host='127.0.0.1', database='lianjia', user='root', password='123456')
        self.cursor=self.conn.cursor()

    def process_item(self, item, spider):
        with open("ershoufang.json","a+")as f:  # 前端后端数据的交换格式
            f.write(str(item._values))




        insert_sql = "insert into info (name,price,room_num,area,ori,position,uniprice) values (%s,%s,%s,%s,%s,%s,%s)"

        # 执行插入数据到数据库操作
        self.cursor.execute(insert_sql, (item['name'], item['price'], item['room_nums'], item['area'],item['ori'],item['position'],item['uniprice']))
        # 提交,不进行提交无法保存到数据库
        self.conn.commit()

        return item

6、可视化.py

import pymysql

def select():
    nums = []
    positions=[]
    connect = pymysql.connect(host='127.0.0.1', database='lianjia', user='root', password='123456')
    sql = "select position,count(*) from info group by position having count(*)>100"
    cursor = connect.cursor()
    cursor.execute(sql)
    for row in cursor.fetchall():
        position = row[0]
        num = row[1]
        nums.append(num)
        positions.append(position)
    cursor.close()
    connect.close()

    # print(positions)
    # print(nums)
    return positions,nums

7、pyecharts制图

#coding=gbk
from pyecharts.charts import Bar    #柱状图的
from pyecharts import options   #标题设置的
from FinalProject.可视化 import select

position,num = select() #获取数据库数据

bar = Bar()

#添加标题
bar.set_global_opts(
    title_opts=options.TitleOpts(title="柱状图",subtitle="各地区二手房分布"),
)

#x轴显示地区
bar.add_xaxis(position)
#y轴显示数量
bar.add_yaxis("数量",num)
# 生成的html文件
bar.render("positionInfo.html")
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值