当前位置:   article > 正文

链家网爬取深圳租房信息并存入MySQL_爬取链家并保存在数据库

爬取链家并保存在数据库

0 爬前工作

决定毕业后前往深圳工作,想要了解深圳的租房市场。通过结合网上对链家网爬取经验,开始自己的爬取工作

分析URL

  • https://sz.lianjia.com/zufang/
    其中,sz是城市,如想获得其它城市可以更换;zufang表示租房
  • https://sz.lianjia.com/zufang/luohuqu/
    限定罗湖区后,URL增加luohuqu,想要那个区加上那个区的拼音
  • https://sz.lianjia.com/zufang/luohuqu/rt200600000001/
    限定整租后,URL增加rt200600000001,类型:整租:rt200600000001 合租:rt200600000002
  • https://sz.lianjia.com/zufang/luohuqu/pg2rt200600000002/#contentList
    打开第二页后,URL增加pg2

后继还有租金、户型、朝向等不做限定

宽表设计

浏览网页后根据自己分析需要设计了如下宽表:

district1 区district2 区域address 详细地址rentType 出租类型size 大小toward 朝向zone 格局price 价格tag 标签

需要用到的包

import requests # 爬取网站
from bs4 import BeautifulSoup # 解析超文本
import re # 正则
import pymysql # 连接MySQL
import time # 时间限制
  • 1
  • 2
  • 3
  • 4
  • 5

1 解析网页

1.0 查看单个网页是否爬取成功

District = "luohuqu"
page = 2
RentType = "rt200600000002"
URL = "https://sz.lianjia.com/zufang/{}/pg{}{}/#contentList".format(District, page, RentType)
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36"
           ,"Connection":"close"}
res = requests.get(URL, headers = headers)
print("URL = " + res.url)
print(res.text)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

打印出来的网址能正常打开,超文本的输出也跟网站上查看的一样,可以看出链家网的爬取有URL请求头就可以爬取到,极大方便了爬虫
接着进入下一步

1.1 解析URL

  • 输入:URL(连接)、headers(请求头)
  • 输出:soup(解析超文本后的格式)
  • request.get()爬取网站
  • BeautifulSoup解析超文本
def parseURL(URL, headers):
    time.sleep(10) ## 时间限流,避免被反爬虫
    try: ## 避免访问太快失败整个程序退出
        res = requests.get(URL, headers = headers)
        if (res.status_code==200):
            html = res.text
            soup = BeautifulSoup(html, 'lxml')
            return soup
        else:
            print("访问{}失败".format(URL))
            return None
    except:
        time.sleep(20)
        print("访问{}失败".format(URL))
        return None
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

lxml解析器有解析HTML和XML的功能,而且速度快,容错能力强

1.2 获取限制区和出租类型后的总套数

在这里插入图片描述
可以看到总套数在以上attrs中
注意class是python固定语言,在后面加个"_"

totalFind = int(soup.find('span', class_="content__title--hl").get_text()) # 获取文本后是str类型,需转换成int才能比较大小
  • 1

get_text()可以获取文本,返回str类型

1.3 获取总页数

在这里插入图片描述
因为总页数不在文本里,所以采用先获取该结点,再用正则匹配

  • 输入:soup(解析超文本后的格式)
  • 输出:totalPage(总页数)
def TotalPage(soup):
    pg_content = soup.find_all('div',  class_="content__pg")[0] ## 获取结点
    totalPage = re.search('data-totalpage="(\d+)".*', str(pg_content)).group(1) ## 总页数不在文本里,所以需要正则来查找
    return totalPage
  • 1
  • 2
  • 3
  • 4

1.4 获取非首页的网址

增加:page

  • 输入:District(区)、page(第几页)、RentType(出租类型)
  • 输出:URL
def getURL(District, page, RentType):
    URL = "https://sz.lianjia.com/zufang/{}/pg{}{}/#contentList".format(District, page, RentType)
    return URL
  • 1
  • 2
  • 3

1.5 获取信息

在这里插入图片描述
同一页面的每一套租房信息都在这种结点中,先找到所有这种结点
再根据宽表的设计找出需要信息的位置,进行提取

  • 输入:house(每套的结点)
  • 输出:data(信息数据)
def getMessage(house):
    title = house.find('p', class_="content__list--item--title twoline").get_text(strip=True) ##strip=True:去除获得文本内容的前后空白
    rentType = re.split(r'[·]', title)[0] ## 出租类型
    message = house.find('p',  class_="content__list--item--des").get_text(strip=True)
    message = re.split(r'[-/]', message)
    if (len(message)==7):
        district1 = message[0]  ##  区
        district2 = message[1] ## 进一步地址
        address = message[2] ## 小区
        size = message[3].replace("㎡", "") ## 大小,并把单位换掉
        toward = message[4] ## 朝向
        zone = message[5] ##  格局
        tag = house.find('p', class_="content__list--item--bottom oneline").get_text(strip=True) ## 标签
        price = house.find('span', class_="content__list--item-price").get_text(strip=True).replace("元/月", "") ## 价格
        data = {'district1': district1
                ,'district2': district2
                ,'address': address
                ,'rentType': rentType
                ,'size':size
                ,'toward': toward
                ,'zone': zone
                ,'price': price
                ,'tag': tag
               }
        return data
    else: 
        return None
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

2 导入数据库

2.1 创建数据库

  • 输入:dbName(数据库名字)
  • 输入:None
def createDB(dbName):
    db = pymysql.connect(host=localhost ,user='root', password='***', port=3306) # localhost填写你的主机名/IP;password填写你MySQL的密码
    cursor = db.cursor()
    sql = "CREATE DATABASE {} DEFAULT CHARACTER SET utf8".format(dbName)
    cursor.execute(sql)
    db.close()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.2 创建表

  • 输入:dbName(数据库名称)、tableName(表名称)
  • 输出:None
def createTable(dbName, tableName):
    db = pymysql.connect(host=localhost, user='root', password='***', port=3306, db=dbName)
    cursor = db.cursor()
    sql = '''create table if not exists {}
    (
     district1 	VARCHAR(255)
    ,district2	VARCHAR(255)
    ,address		VARCHAR(255)
    ,renttype	VARCHAR(255)
    ,size			VARCHAR(255)
    ,toward		VARCHAR(255)
    ,zone			VARCHAR(255)
    ,price		VARCHAR(255)
    ,tag			VARCHAR(255)
    );'''.format(tableName)
    cursor.execute(sql)
    db.close()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

插入数据

  • 输入:dbName(数据库名称)、tableName(表名称)、data(信息数据)
  • 输出:None
def InsertToSql(dbName, tableName, data):
    keys = ', '.join(data.keys())
    values = ', '.join(['%s'] * len(data))
    db = pymysql.connect(host=localhost, user='root', password='***', port=3306, db=dbName)
    cursor = db.cursor()
    sql = 'INSERT INTO {table}({keys}) VALUES ({values})'.format(table=tableName, keys=keys, values=values)
    try:
        if cursor.execute(sql, tuple(data.values())):
            print('Successful')
            db.commit()
    except:
        print('Failed')
        db.rollback()
    db.close()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3 尝试爬取

dbName = 'test1' ## 数据库名称
tableName = 'test1' ## 创建表名称
createDB(dbName) ## 创建数据库
createTable(dbName, tableName) ## 创建表

District = Districts[6] ## 区
RentType = RentTypes[1] ## 出租类型

URL = "https://sz.lianjia.com/zufang/{}/{}/".format(District, RentType)
soup = parseURL(URL, headers)
if (soup != None):
    totalFind = int(soup.find('span', class_="content__title--hl").get_text()) ## 找到总套数
    if (totalFind !=0):
        totalPage = int(TotalPage(soup))
        print("{} {} 共找到 {} 套".format(District, RentType, totalFind))
        houseElements = soup.find_all('div', class_="content__list--item")
        i = 1
        for house in houseElements:
            data = getMessage(house)
            if (data !=None):
                InsertToSql(dbName, tableName, data)
                print("写入第{}套".format(i))
                i += 1
        if (totalPage > 1):
            for page in range(2, totalPage+2):
                URL = getURL(District=District, page=page, RentType=RentType)
                soup = parseURL(URL, headers)
                if (soup != None):
                    houseElements = soup.find_all('div', class_="content__list--item")
                    for house in houseElements:
                        data = getMessage(house)
                        InsertToSql(dbName, tableName, data)
                        print("写入第{}套".format(i))
                        i += 1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

4 总代码

# 需要导入的包
import requests
from bs4 import BeautifulSoup
import re
import pymysql
import time


# 需要限制的东西
Districts = ['luohuqu', 'futianqu', 'nanshanqu', 'yantianqu', 'baoanqu', 'longgangqu', 'longhuaqu', 'guangmingqu', 'pingshanqu', 'dapengxinqu'] # 深圳的各个区的拼音
RentTypes = ['rt200600000001', 'rt200600000002'] # 出租类型
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36"
           ,"Connection":"close"}


# 得到非首页的网址
def getURL(District, page, RentType):
    URL = "https://sz.lianjia.com/zufang/{}/pg{}{}/#contentList".format(District, page, RentType)
    return URL


# 解析URL
def parseURL(URL, headers):
    time.sleep(10)
    try:
        res = requests.get(URL, headers = headers)
        if (res.status_code==200):
            html = res.text
            soup = BeautifulSoup(html, 'lxml')
            return soup
        else:
            print("访问{}失败".format(URL))
            return None
    except:
        time.sleep(20)
        print("访问{}失败".format(URL))
        return None
    

# 总页数
def TotalPage(soup):
    pg_content = soup.find_all('div',  class_="content__pg")[0]
    totalPage = re.search('data-totalpage="(\d+)".*', str(pg_content)).group(1)
    return totalPage


# 得到具体信息
def getMessage(house):
    title = house.find('p', class_="content__list--item--title twoline").get_text(strip=True) ##strip=True:去除获得文本内容的前后空白
    rentType = re.split(r'[·]', title)[0] ## 出租类型
    message = house.find('p',  class_="content__list--item--des").get_text(strip=True)
    message = re.split(r'[-/]', message)
    if (len(message)==7):
        district1 = message[0]  ##  区
        district2 = message[1] ## 进一步地址
        address = message[2] ## 小区
        size = message[3].replace("㎡", "") ## 大小
        toward = message[4] ## 朝向
        zone = message[5] ##  格局
        tag = house.find('p', class_="content__list--item--bottom oneline").get_text(strip=True) ## 标签
        price = house.find('span', class_="content__list--item-price").get_text(strip=True).replace("元/月", "") ## 价格
        data = {'district1': district1
                ,'district2': district2
                ,'address': address
                ,'rentType': rentType
                ,'size':size
                ,'toward': toward
                ,'zone': zone
                ,'price': price
                ,'tag': tag
               }
        return data
    else: 
        return None
    
    
# 创建数据库
def createDB(dbName):
    db = pymysql.connect(db = pymysql.connect(host=localhost, user='root', password='***', port=3306, db=dbName))
    cursor = db.cursor()
    sql = "CREATE DATABASE {} DEFAULT CHARACTER SET utf8".format(dbName)
    cursor.execute(sql)
    db.close()
    
    
# 创建表
def createTable(dbName, tableName):
    db = pymysql.connect(host='127.0.0.1', user='root', password='123456', port=3306, db=dbName)
    cursor = db.cursor()
    sql = '''create table if not exists {}
    (
     district1 	VARCHAR(255)
    ,district2	VARCHAR(255)
    ,address		VARCHAR(255)
    ,renttype	VARCHAR(255)
    ,size			VARCHAR(255)
    ,toward		VARCHAR(255)
    ,zone			VARCHAR(255)
    ,price		VARCHAR(255)
    ,tag			VARCHAR(255)
    );'''.format(tableName)
    cursor.execute(sql)
    db.close()
    
    
# 数据导入
def InsertToSql(dbName, tableName, data):
    keys = ', '.join(data.keys())
    values = ', '.join(['%s'] * len(data))
    db = pymysql.connect(host='127.0.0.1', user='root', password='123456', port=3306, db=dbName)
    cursor = db.cursor()
    sql = 'INSERT INTO {table}({keys}) VALUES ({values})'.format(table=tableName, keys=keys, values=values)
    try:
        if cursor.execute(sql, tuple(data.values())):
            db.commit()
    except:
        print('Failed')
        db.rollback()
    db.close()


# 主函数
dbName = 'lianjiawang' ## 数据库名称
tableName = 'zufang_sz1' ## 创建表名称
## createDB(dbName) ## 创建数据库
createTable(dbName, tableName) ## 创建表

# District = Districts[6] ## 区
# RentType = RentTypes[1] ## 出租类型

for District in Districts:
    for RentType in RentTypes:
        URL = "https://sz.lianjia.com/zufang/{}/{}/".format(District, RentType)
        soup = parseURL(URL, headers)
        if (soup != None):
            totalFind = int(soup.find('span', class_="content__title--hl").get_text()) ## 找到总套数
            if (totalFind !=0):
                totalPage = int(TotalPage(soup))
                # print("{} {} 共找到 {} 套".format(District, RentType, totalFind))
                houseElements = soup.find_all('div', class_="content__list--item")
                i = 1
                for house in houseElements:
                    data = getMessage(house)
                    if (data !=None):
                        InsertToSql(dbName, tableName, data)
                        # print("写入第{}套".format(i))
                        i += 1
                if (totalPage > 1):
                    for page in range(2, totalPage+2):
                        URL = getURL(District=District, page=page, RentType=RentType)
                        soup = parseURL(URL, headers)
                        if (soup != None):
                            houseElements = soup.find_all('div', class_="content__list--item")
                            for house in houseElements:
                                data = getMessage(house)
                                if(data != None):
                                    InsertToSql(dbName, tableName, data)
                                    #print("写入第{}套".format(i))
                                    #i += 1
        print("深圳{} 租房类型:{}爬取成功".format(District, RentType))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/196566
推荐阅读
相关标签
  

闽ICP备14008679号