2023年11月28日发(作者:)

【爬⾍】应⽤Python爬⾍爬取⾖瓣租房上的帖⼦信息

⽬录

⼀、项⽬简介

1.1 简介

    本项⽬应⽤Python爬⾍、Flask框架、Echarts、WordCloud等技术将⾖瓣租房信息爬取出来保存于Excel和数据库中,进⾏数据可视

化操作、制作⽹页展⽰。

    主要内容包括三部分:

:Python 爬⾍将 上的租房信息爬取出来,解析数据后将其存储于Excel和SQLite数据库中。

:测试使⽤Flask框架。

:应⽤Flask框架、Echarts、WordCloud技术将数据库中的租房信息以⽹页的形式展⽰出来。

1.2 Results

import sys

from bs4 import BeautifulSoup #

⽹页解析,获取数据

import re #

正则表达式,进⾏⽂件匹配

import urllib # URL

制定,获取⽹页数据

import urllib.request

import urllib.error

import xlwt # excel

进⾏操作

import sqlite3 # SQLite

进⾏数据库操作

需要安装requests、urllib3、xlwt和pysqlite3库,在终端执⾏⼀下命令。

pip install requests urllib3 xlwt pysqlite3

2.2 准备⼯作

    URL分析:

    总结:

    1)页⾯包含x条租房数据,每页25条,

    2)每页的URL的不同之处:最后的数值 = (页数 - 1) * 25。

# 1. 2

爬取⽹页、逐⼀解析⽹页数据

baseurl = '/group/558444/discussion?start=' # URL

基本

pagecount = 10 #

爬取的⽹页数量

num = 25 #

每页的帖⼦数

datalist = getData(baseurl, pagecount, num) #

爬取⽹页、解析数据

# pagecount

调⽤获取页⾯信息的函数

for i in range(0, pagecount):

url = baseurl + str(i * num) #

拼接⽹页链接

# 1.

爬取⽹页

html = askURL(url) #

保存获取到的⽹页源码

2.2.1 分析页⾯

    1)借助Chrome开发者⼯具(F12)来分析页⾯,在Elements下找到需要的数据位置。

    2)在页⾯中选择⼀个元素以进⾏检查(Ctrl+Shift+C)(开发者⼯具最左上⽅的⼩箭头),点击页⾯内容即可定位到具体标签位置。

    3)点击Network,可以查看每个时间点发送的请求和交互情况,可点击最上⽅⼩红点(停⽌记录⽹络⽇志Ctrl+E)停⽌交互。

    4)Headers查看发送给服务器的命令情况。

    5)服务器返回信息可在Response中查看。

2.2.2 编码规范

    1)⼀般Python程序第⼀⾏需要加⼊

# -*- coding = utf-8 -*-

    这样可以在代码中包含中⽂。

    2)使⽤函数实现单⼀功能或相关联功能的代码段,可以提⾼可读性和代码重复利⽤率。

    3)Python⽂件中可以加⼊main函数⽤于测试程序

if __name__ == "__main__":

    4)Python使⽤#添加注释,说明代码(段)的作⽤。

2.2.3 引⼊模块

    sys, bs4 -> BeautifulSoup, re, urllib, xlwt。

2.3 获取数据

    python⼀般使⽤urllib库获取页⾯。

    获取页⾯数据:

    1)对每⼀个页⾯,调⽤askURL函数获取页⾯内容

def askURL(url):

"""

得到指定⼀个URL的⽹页信息

:param url: ⽹页链接

:return:

"""

#

模拟浏览器头部信息,向⾖瓣服务器发送消息

head = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 Edg/83.0.47

8.37'

} #

⽤户代理,表⽰告诉⾖瓣服务器,我们是什么类型的机器、浏览器(本质上是告诉浏览器,我们可以接收什么⽔平的⽂件内容)

    3)t⽣成请求,n发送请求获取响应,read获取页⾯内容

request = urllib.request.Request(url, headers=head) #

发送请求

html = ''

    4)在访问页⾯时经常会出现错误,为了程序正常运⾏,假如异常捕获try…except…语句

#

捕获异常

try:

response = urllib.request.urlopen(request) #

取得响应

html = response.read().decode('utf-8') #

获取⽹页内容

# print(html)

except urllib.error.URLError as e: #

若发⽣异常,则打印相关信息

if hasattr(e, 'code'): #

异常代码

print(e.code)

if hasattr(e, 'reason'): #

异常原因

print(e.reason)

return html

2.4 解析内容

    对爬取的html⽂件进⾏解析

    1、使⽤BeautifulSoup定位特定的标签位置

# 2.

逐⼀解析数据

soup = BeautifulSoup(html, '') #

对⽹页源码进⾏解析

# print(soup) # html

测试是否能被解析

    2、使⽤正则表达式找到具体的内容

for item in soup.find_all('tr', class_=''): #

找到每⼀个帖⼦选项(查找符合要求的字符串,形成列表)

# print(item) # item

测试:查看全部信息

data = []

item = str(item) #

转换成字符串

# print(item) # item

测试

#

帖⼦名

title = re.findall(findTitle, item)[0]

# print(title) # title

测试:查看

data.append(title) #

添加帖⼦名

#

帖⼦详情链接

link = re.findall(findLink, item)

# print(link) # link

测试:查看信息

#

进⼊帖⼦⾥爬取租房信息介绍内容和照⽚

info, imglink = getInfo(link[0])

data.append(info) #

添加详细信息

data.append(imglink) #

添加图⽚链接

if (len(link) == 2):

data.append(link[0]) #

添加详情链接

# alink = l(findLink, item)[1]

# print(alink) # link

测试:查看信息

data.append(link[1]) #

添加发帖⼈主页链接

else:

data.append(link[0])

data.append(' ') #

留空

#

回帖数

rcount = re.findall(findRCount, item)[0]

# print(rcount) #

测试:查看回帖数

if rcount == '':

# print(0) #

测试:查看回帖数

data.append(0) #

添加回帖数

else:

# print(rcount) #

测试:查看回帖数

data.append(int(rcount)) #

添加回帖数

#

最后回帖时间

rtime = re.findall(findRTime, item)[0]

# print(rtime)

data.append(rtime) #

添加最后回帖时间

# otitle = titles[1].replace('/', '') # ()

去掉⽆关符号,或

datalist.append(data) # datalist

把处理好的信息放⼊

# print(datalist) #

测试

2.5 保存数据

    Excel表格存储:利⽤python库xlwt将抽取的数据datalist写⼊Excel表格。

def saveData(datalist, pagecount, num, savepath):

"""

将解析后的数据保存在Excel⽂件中

:param datalist: ⽹页解析后的数据

:param pagecount: 爬取的⽹页数量

:param num: 每页的帖⼦数

:param savepath: Excel⽂件保存路径

:return:

"""

# print('')

book = xlwt.Workbook(encoding='utf-8', style_compression=0) # workbook

新建

sheet = book.add_sheet('⾖瓣租房信息', cell_overwrite_ok=True) # sheet

添加

#

列名

col = ('序号', '帖⼦名', '详细介绍', '图⽚链接', '帖⼦详情链接', '发帖⼈主页链接', '回帖数', '最后回帖时间')

#

写⼊列名

for i in range(0, len(col)):

sheet.write(0, i, col[i])

# Excel

将每条帖⼦的相关内容写⼊对应⾏中

for i in range(0, pagecount*num):

# print('%d' % (i+1))

data = datalist[i]

sheet.write(i+1, 0, i+1) #

写⼊序号

for j in range(0, len(data)):

sheet.write(i+1, j+1, data[j]) #

写⼊数据

book.save(savepath) #

保存⽂件

# print('Successful!')

    数据库存储

def saveData2DB(datalist, dbpath):

"""

将解析后的数据保存在数据库⽂件中

:param datalist: ⽹页解析后的数据

:param dbpath: 数据库⽂件保存路径

:return:

"""

init_DB(dbpath) #

初始化数据库

conn = sqlite3.connect(dbpath) #

连接数据库

cur = conn.cursor() #

获取游标

#

将数据逐⼀保存到数据库中

for data in datalist:

for index in range(len(data)):

if index != 5: # index5int

的数据类型是

data[index] = '"'+data[index]+'"' #

每项的字符串需要加上双引号或单引号

#

插⼊字符串,以逗号隔开

sql = '''

insert into renting(

title, introduction, img_link, title_link, person_link, re_count, re_time)

values(%s)''' % ",".join(str(v) for v in data)

# print(sql)

cur.execute(sql) #

执⾏数据库操作

conn.commit() #

提交

cur.close() #

关闭游标

conn.close() #

关闭连接

2.7 ⽹页展⽰数据

待更新

2.8 TODO

添加筛选:区域、⼩区名、地铁站等

定义类,获取各种不同途径信息(⾖瓣、⾃如、链家、贝壳等)

三、完整代码

# -*- coding = utf-8 -*-

# @Time: 2020/5/30 19:57

# @Author: Donvink

# @File:

# @Software: PyCharm

"""

查看robots协议:/

零、流程

准备⼯作 -> 获取数据 -> 解析内容 -> 保存数据

⼀、准备⼯作

URL分析:

⾸页 /group/558444/ (包含50条数据,和第⼀第⼆页数据相同)

第⼀页 /group/558444/discussion?start=0

第⼆页 /group/558444/discussion?start=25

1)页⾯包含x条租房数据,每页25

2)每页的URL的不同之处:最后的数值 = (页数 - 1) * 25

1、分析页⾯

1)借助Chrome开发者⼯具(F12)来分析页⾯,在Elements下找到需要的数据位置。

2)在页⾯中选择⼀个元素以进⾏检查(Ctrl+Shift+C)(开发者⼯具最左上⽅的⼩箭头),点击页⾯内容即可定位到具体标签位置。

3)点击Network,可以查看每个时间点发送的请求和交互情况,可点击最上⽅⼩红点(停⽌记录⽹络⽇志Ctrl+E)停⽌交互。

4Headers查看发送给服务器的命令情况。

5)服务器返回信息可在Response中查看。

2、编码规范

1)⼀般Python程序第⼀⾏需要加⼊

# -*- coding = utf-8 -*-

这样可以在代码中包含中⽂。

2)使⽤函数实现单⼀功能或相关联功能的代码段,可以提⾼可读性和代码重复利⽤率。

3Python⽂件中可以加⼊main函数⽤于测试程序

if __name__ == "__main__":

4Python使⽤#添加注释,说明代码(段)的作⽤

3、引⼊模块

sys, bs4 -> BeautifulSoup, re, urllib, xlwt

⼆、获取数据

python⼀般使⽤urllib库获取页⾯

获取页⾯数据:

1)对每⼀个页⾯,调⽤askURL函数获取页⾯内容

2)定义⼀个获取页⾯的函数askURL,传⼊⼀个url参数,表⽰⽹址,如/group/558444/discussion?start=0

3t⽣成请求,n发送请求获取响应,read获取页⾯内容

4)在访问页⾯时经常会出现错误,为了程序正常运⾏,假如异常捕获pt...语句

三、解析内容

对爬取的html⽂件进⾏解析

1、使⽤BeautifulSoup定位特定的标签位置

2、使⽤正则表达式找到具体的内容

四、保存数据

Excel表格存储:利⽤pythonxlwt将抽取的数据datalist写⼊Excel表格

TODO

1、添加筛选【区域,⼩区名,地铁站】

2、定义类,获取各种不同途径信息(⾖瓣,⾃如,链家,贝壳)

"""

import sys

from bs4 import BeautifulSoup #

⽹页解析,获取数据

import re #

正则表达式,进⾏⽂件匹配

import urllib # URL

制定,获取⽹页数据

import urllib.request

import urllib.error

import xlwt # excel

进⾏操作

import sqlite3 # SQLite

进⾏数据库操作

def main():

def main():

"""

主函数⼊⼝

1.爬取⽹页

2.逐⼀解析数据

3.保存数据

:return:

"""

print('开始爬取······')

# 1. 2

爬取⽹页、逐⼀解析⽹页数据

baseurl = '/group/558444/discussion?start=' # URL

基本

pagecount = 10 #

爬取的⽹页数量

num = 25 #

每页的帖⼦数

datalist = getData(baseurl, pagecount, num) #

爬取⽹页、解析数据

# 3.

保存数据

savepath = 'douban_' # Excel

⽂件保存路径

saveData(datalist, pagecount, num, savepath) # Excel

将数据保存在

dbpath = 'douban_' #

数据库⽂件保存路径

saveData2DB(datalist, dbpath) #

将数据保存在数据库中

# askURL('/group/558444/discussion?start=0') # askURL

测试

print('爬取完毕!')

def getData(baseurl, pagecount, num):

"""

爬取⽹页,逐⼀对⽹页数据进⾏分析。主要内容有:

'帖⼦名', '详细介绍', '图⽚链接', '帖⼦详情链接', '发帖⼈主页链接', '回帖数', '最后回帖时间'

:param baseurl: 基本URL

:param pagecount: 爬取的⽹页数量

:param num: 每页的帖⼦数

:return:

"""

datalist = []

#

正则表达式规则

findTitle = re.compile(r'title="(.*?)"', re.S) # n

找到帖⼦名,有的帖⼦名带有

findLink = re.compile(r'href="(.*?)"') #

找到帖⼦详情链接

findRCount = re.compile(r'<.*class="r-count".*>(.*?)') #

找到回帖数

findRTime = re.compile(r'<.*class="time".*">(.*?)') #

找到最后回帖时间

# .*s

注意:正则表达式匹配空格时,需⽤匹配

# pagecount

调⽤获取页⾯信息的函数

for i in range(0, pagecount):

url = baseurl + str(i * num) #

拼接⽹页链接

# 1.

爬取⽹页

html = askURL(url) #

保存获取到的⽹页源码

# 2.

逐⼀解析数据

soup = BeautifulSoup(html, '') #

对⽹页源码进⾏解析

# print(soup) # html

测试是否能被解析

for item in soup.find_all('tr', class_=''): #

找到每⼀个帖⼦选项(查找符合要求的字符串,形成列表)

# print(item) # item

测试:查看全部信息

data = []

item = str(item) #

转换成字符串

# print(item) # item

测试

#

帖⼦名

title = re.findall(findTitle, item)[0]

# print(title) # title

测试:查看

data.append(title) #

添加帖⼦名

#

帖⼦详情链接

link = re.findall(findLink, item)

link = re.findall(findLink, item)

# print(link) # link

测试:查看信息

#

进⼊帖⼦⾥爬取租房信息介绍内容和照⽚

info, imglink = getInfo(link[0])

data.append(info) #

添加详细信息

data.append(imglink) #

添加图⽚链接

if (len(link) == 2):

data.append(link[0]) #

添加详情链接

# alink = l(findLink, item)[1]

# print(alink) # link

测试:查看信息

data.append(link[1]) #

添加发帖⼈主页链接

else:

data.append(link[0])

data.append(' ') #

留空

#

回帖数

rcount = re.findall(findRCount, item)[0]

# print(rcount) #

测试:查看回帖数

if rcount == '':

# print(0) #

测试:查看回帖数

data.append(0) #

添加回帖数

else:

# print(rcount) #

测试:查看回帖数

data.append(int(rcount)) #

添加回帖数

#

最后回帖时间

rtime = re.findall(findRTime, item)[0]

# print(rtime)

data.append(rtime) #

添加最后回帖时间

# otitle = titles[1].replace('/', '') # ()

去掉⽆关符号,或

datalist.append(data) # datalist

把处理好的信息放⼊

# print(datalist) #

测试

return datalist

def getInfo(url):

"""

进⼊每个帖⼦⾥爬取租房信息介绍内容和照⽚链接

:param url: 帖⼦URL

:return:

"""

tempinfo = []

info = '' #

租房详细信息介绍

tempimglink = []

imglink = '' #

图⽚链接

#

正则表达式规则

findInfo = re.compile(r'

(.*?)

', re.S) # n

找到帖⼦详情信息,有的帖⼦名带有

findImgLink = re.compile(r'src="(.*?)"') #

找到帖⼦附带的照⽚链接

html = askURL(url) #

保存获取到的⽹页源码

soup = BeautifulSoup(html, '') #

解析⽹页源码

topic = soup.find_all('div', class_='topic-richtext') #

找到介绍内容和照⽚所在标签

topic = str(topic) #

转换为字符串

#

详细介绍

tempinfo = re.findall(findInfo, topic)

info = " , ".join(str(v) for v in tempinfo) #

帖⼦⾥详细介绍内容会有换⾏,⽤逗号隔开

#

照⽚链接

tempimglink = re.findall(findImgLink, topic)

imglink = " , ".join(str(v) for v in tempimglink) #

每个帖⼦可能会附带多张照⽚,⽤逗号隔开

return info, imglink

return info, imglink

def askURL(url):

"""

得到指定⼀个URL的⽹页信息

:param url: ⽹页链接

:return:

"""

#

模拟浏览器头部信息,向⾖瓣服务器发送消息

head = {

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 Edg/83.0.47

8.37'

} #

⽤户代理,表⽰告诉⾖瓣服务器,我们是什么类型的机器、浏览器(本质上是告诉浏览器,我们可以接收什么⽔平的⽂件内容)

request = urllib.request.Request(url, headers=head) #

发送请求

html = ''

#

捕获异常

try:

response = urllib.request.urlopen(request) #

取得响应

html = response.read().decode('utf-8') #

获取⽹页内容

# print(html)

except urllib.error.URLError as e: #

若发⽣异常,则打印相关信息

if hasattr(e, 'code'): #

异常代码

print(e.code)

if hasattr(e, 'reason'): #

异常原因

print(e.reason)

return html

def saveData(datalist, pagecount, num, savepath):

"""

将解析后的数据保存在Excel⽂件中

:param datalist: ⽹页解析后的数据

:param pagecount: 爬取的⽹页数量

:param num: 每页的帖⼦数

:param savepath: Excel⽂件保存路径

:return:

"""

# print('')

book = xlwt.Workbook(encoding='utf-8', style_compression=0) # workbook

新建

sheet = book.add_sheet('⾖瓣租房信息', cell_overwrite_ok=True) # sheet

添加

#

列名

col = ('序号', '帖⼦名', '详细介绍', '图⽚链接', '帖⼦详情链接', '发帖⼈主页链接', '回帖数', '最后回帖时间')

#

写⼊列名

for i in range(0, len(col)):

sheet.write(0, i, col[i])

# Excel

将每条帖⼦的相关内容写⼊对应⾏中

for i in range(0, pagecount*num):

# print('%d' % (i+1))

data = datalist[i]

sheet.write(i+1, 0, i+1) #

写⼊序号

for j in range(0, len(data)):

sheet.write(i+1, j+1, data[j]) #

写⼊数据

book.save(savepath) #

保存⽂件

# print('Successful!')

def saveData2DB(datalist, dbpath):

"""

将解析后的数据保存在数据库⽂件中

:param datalist: ⽹页解析后的数据

:param dbpath: 数据库⽂件保存路径

:return:

"""

"""

init_DB(dbpath) #

初始化数据库

conn = sqlite3.connect(dbpath) #

连接数据库

cur = conn.cursor() #

获取游标

#

将数据逐⼀保存到数据库中

for data in datalist:

for index in range(len(data)):

if index != 5: # index5int

的数据类型是

data[index] = '"'+data[index]+'"' #

每项的字符串需要加上双引号或单引号

#

插⼊字符串,以逗号隔开

sql = '''

insert into renting(

title, introduction, img_link, title_link, person_link, re_count, re_time)

values(%s)''' % ",".join(str(v) for v in data)

# print(sql)

cur.execute(sql) #

执⾏数据库操作

conn.commit() #

提交

cur.close() #

关闭游标

conn.close() #

关闭连接

def init_DB(dbpath):

"""

初始化数据库

:param dbpath: 数据库保存路径

:return:

"""

# create table renting

# if not existsdatabasesql

若不加,则每次运⾏程序需要先删除;否则不⽤先删除,但⽆法更新⾥的格式

sql = '''

create table if not exists renting

(

id integer primary key autoincrement,

title text,

introduction text,

img_link text,

title_link text,

person_link text,

re_count numeric,

re_time text

)

''' #

创建数据表

conn = sqlite3.connect(dbpath) #

创建或连接数据库

cursor = conn.cursor() #

获取游标

cursor.execute(sql) #

执⾏数据库操作

conn.commit() #

提交

cursor.close() #

关闭游标

conn.close() #

关闭

if __name__ == "__main__": #

当程序执⾏时

#

调⽤函数

main()

# init_DB('.db') #

租房测试初始化数据库