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)停⽌交互。
4)Headers查看发送给服务器的命令情况。
5)服务器返回信息可在Response中查看。
2、编码规范
1)⼀般Python程序第⼀⾏需要加⼊
# -*- coding = utf-8 -*-
这样可以在代码中包含中⽂。
2)使⽤函数实现单⼀功能或相关联功能的代码段,可以提⾼可读性和代码重复利⽤率。
3)Python⽂件中可以加⼊main函数⽤于测试程序
if __name__ == "__main__":
4)Python使⽤#添加注释,说明代码(段)的作⽤
3、引⼊模块
sys, bs4 -> BeautifulSoup, re, urllib, xlwt
⼆、获取数据
python⼀般使⽤urllib库获取页⾯
获取页⾯数据:
1)对每⼀个页⾯,调⽤askURL函数获取页⾯内容
2)定义⼀个获取页⾯的函数askURL,传⼊⼀个url参数,表⽰⽹址,如/group/558444/discussion?start=0
3)t⽣成请求,n发送请求获取响应,read获取页⾯内容
4)在访问页⾯时经常会出现错误,为了程序正常运⾏,假如异常捕获pt...语句
三、解析内容
对爬取的html⽂件进⾏解析
1、使⽤BeautifulSoup定位特定的标签位置
2、使⽤正则表达式找到具体的内容
四、保存数据
Excel表格存储:利⽤python库xlwt将抽取的数据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' (.*?)
找到帖⼦详情信息,有的帖⼦名带有
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') #
租房测试初始化数据库
发布评论