700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 【爬虫】应用Python爬虫爬取豆瓣租房上的帖子信息

【爬虫】应用Python爬虫爬取豆瓣租房上的帖子信息

时间:2019-01-25 00:36:38

相关推荐

【爬虫】应用Python爬虫爬取豆瓣租房上的帖子信息

GitHub项目地址:/Donvink/Spider.BC

哔哩哔哩代码讲解:https://b23.tv/waSfUa

CSDN博客地址:/sinat_16020825/article/details/108538779

目录

一、项目简介1.1 简介1.2 Results1.2.1 Excel保存数据1.2.2 网页展示数据二、代码分析2.1 概述2.1.1 robots协议2.1.2 爬取流程2.2 准备工作2.2.1 分析页面2.2.2 编码规范2.2.3 引入模块2.3 获取数据2.4 解析内容2.5 保存数据2.7 网页展示数据2.8 TODO三、完整代码

一、项目简介

1.1 简介

    本项目应用Python爬虫、Flask框架、Echarts、WordCloud等技术将豆瓣租房信息爬取出来保存于Excel和数据库中,进行数据可视化操作、制作网页展示。

    主要内容包括三部分:

douban_renting:Python 爬虫将 豆瓣租房上的租房信息爬取出来,解析数据后将其存储于Excel和SQLite数据库中。flask_demo:测试使用Flask框架。douban_flask:应用Flask框架、Echarts、WordCloud技术将数据库中的租房信息以网页的形式展示出来。

1.2 Results

1.2.1 Excel保存数据

1.2.2 网页展示数据

首页

帖子列表

词云

二、代码分析

2.1 概述

2.1.1 robots协议

    在爬取数据之前,必须先查看目标网站的robots协议,查阅网站允许和禁止的爬取的数据,对于网站禁止爬虫访问的数据,一定不要去爬取,否则严重的话需要承担相应的法律责任。网站的robots协议地址一般是:https://网站地址/robots.txt。

    豆瓣robots协议地址为:/robots.txt。

    原则上禁止访问robots协议上disallow的地址。

2.1.2 爬取流程

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

    调用的库:

import sysfrom bs4 import BeautifulSoup # 网页解析,获取数据import re # 正则表达式,进行文件匹配import urllib # 制定URL,获取网页数据import urllib.requestimport urllib.errorimport xlwt # 进行excel操作import sqlite3 # 进行SQLite数据库操作

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

pip install requests urllib3 xlwt pysqlite3

2.2 准备工作

    URL分析:

    首页 /group/558444/ (包含50条数据,和第一第二页数据相同);

    第一页 /group/558444/discussion?start=0;

    第二页 /group/558444/discussion?start=25。

    总结:

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

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

# 1.爬取网页 2、逐一解析网页数据baseurl = '/group/558444/discussion?start=' # 基本URLpagecount = 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:"""

    2)定义一个获取页面的函数askURL,传入一个url参数,表示网址,如/group/558444/discussion?start=0

# 模拟浏览器头部信息,向豆瓣服务器发送消息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.478.37'} # 用户代理,表示告诉豆瓣服务器,我们是什么类型的机器、浏览器(本质上是告诉浏览器,我们可以接收什么水平的文件内容)

    3)urllib.Request生成请求,urllib.urlopen发送请求获取响应,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, 'html.parser') # 对网页源码进行解析# 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)# 测试:查看titledata.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 = re.findall(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('/', '') # 去掉无关符号,或re.sub()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('saving...')book = xlwt.Workbook(encoding='utf-8', style_compression=0)# 新建workbooksheet = 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:# index为5的数据类型是intdata[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) # 执行数据库操作mit() # 提交cur.close() # 关闭游标conn.close()# 关闭连接

2.7 网页展示数据

待更新

2.8 TODO

添加筛选:区域、小区名、地铁站等定义类,获取各种不同途径信息(豆瓣、自如、链家、贝壳等)

三、完整代码

# -*- coding = utf-8 -*-# @Time: /5/30 19:57# @Author: Donvink# @File: douban.py# @Software: PyCharm"""查看robots协议:/robots.txt零、流程准备工作 -> 获取数据 -> 解析内容 -> 保存数据一、准备工作URL分析:首页 /group/558444/ (包含50条数据,和第一第二页数据相同)第一页 /group/558444/discussion?start=0第二页 /group/558444/discussion?start=251)页面包含x条租房数据,每页25条2)每页的URL的不同之处:最后的数值 = (页数 - 1) * 251、分析页面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=03)urllib.Request生成请求,urllib.urlopen发送请求获取响应,read获取页面内容4)在访问页面时经常会出现错误,为了程序正常运行,假如异常捕获try...except...语句三、解析内容对爬取的html文件进行解析1、使用BeautifulSoup定位特定的标签位置2、使用正则表达式找到具体的内容四、保存数据Excel表格存储:利用python库xlwt将抽取的数据datalist写入Excel表格TODO:1、添加筛选【区域,小区名,地铁站】2、定义类,获取各种不同途径信息(豆瓣,自如,链家,贝壳)"""import sysfrom bs4 import BeautifulSoup # 网页解析,获取数据import re # 正则表达式,进行文件匹配import urllib # 制定URL,获取网页数据import urllib.requestimport urllib.errorimport xlwt # 进行excel操作import sqlite3 # 进行SQLite数据库操作def main():"""主函数入口1.爬取网页2.逐一解析数据3.保存数据:return:"""print('开始爬取······')# 1.爬取网页 2、逐一解析网页数据baseurl = '/group/558444/discussion?start=' # 基本URLpagecount = 10 # 爬取的网页数量num = 25# 每页的帖子数datalist = getData(baseurl, pagecount, num)# 爬取网页、解析数据# 3.保存数据savepath = 'douban_renting.xls' # Excel文件保存路径saveData(datalist, pagecount, num, savepath) # 将数据保存在Excel中dbpath = 'douban_renting.db'# 数据库文件保存路径saveData2DB(datalist, dbpath) # 将数据保存在数据库中# askURL('/group/558444/discussion?start=0') # 测试askURLprint('爬取完毕!')def getData(baseurl, pagecount, num):"""爬取网页,逐一对网页数据进行分析。主要内容有:'帖子名', '详细介绍', '图片链接', '帖子详情链接', '发帖人主页链接', '回帖数', '最后回帖时间':param baseurl: 基本URL:param pagecount: 爬取的网页数量:param num: 每页的帖子数:return:"""datalist = []# 正则表达式规则findTitle = pile(r'title="(.*?)"', re.S) # 找到帖子名,有的帖子名带有\nfindLink = pile(r'href="(.*?)"')# 找到帖子详情链接findRCount = pile(r'<.*class="r-count".*>(.*?)</td>')# 找到回帖数findRTime = pile(r'<.*class="time".*">(.*?)</td>') # 找到最后回帖时间# 注意:正则表达式匹配空格时,需用.*或\s匹配# 调用获取页面信息的函数pagecount次for i in range(0, pagecount):url = baseurl + str(i * num)# 拼接网页链接# 1.爬取网页html = askURL(url)# 保存获取到的网页源码# 2.逐一解析数据soup = BeautifulSoup(html, 'html.parser') # 对网页源码进行解析# 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)# 测试:查看titledata.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 = re.findall(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('/', '') # 去掉无关符号,或re.sub()datalist.append(data) # 把处理好的信息放入datalist# print(datalist)# 测试return datalistdef getInfo(url):"""进入每个帖子里爬取租房信息介绍内容和照片链接:param url: 帖子URL:return:"""tempinfo = []info = '' # 租房详细信息介绍tempimglink = []imglink = '' # 图片链接# 正则表达式规则findInfo = pile(r'<p>(.*?)</p>', re.S) # 找到帖子详情信息,有的帖子名带有\nfindImgLink = pile(r'src="(.*?)"')# 找到帖子附带的照片链接html = askURL(url) # 保存获取到的网页源码soup = BeautifulSoup(html, 'html.parser')# 解析网页源码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, imglinkdef 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.478.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 htmldef saveData(datalist, pagecount, num, savepath):"""将解析后的数据保存在Excel文件中:param datalist: 网页解析后的数据:param pagecount: 爬取的网页数量:param num: 每页的帖子数:param savepath: Excel文件保存路径:return:"""# print('saving...')book = xlwt.Workbook(encoding='utf-8', style_compression=0)# 新建workbooksheet = 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:# index为5的数据类型是intdata[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) # 执行数据库操作mit() # 提交cur.close() # 关闭游标conn.close()# 关闭连接def init_DB(dbpath):"""初始化数据库:param dbpath: 数据库保存路径:return:"""# create table renting# 若不加if not exists,则每次运行程序需要先删除database;否则不用先删除,但无法更新sql里的格式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) # 执行数据库操作mit() # 提交cursor.close() # 关闭游标conn.close()# 关闭if __name__ == "__main__":# 当程序执行时# 调用函数main()# init_DB('租房.db') # 测试初始化数据库

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。