一、实战场景
Python 如何应用 BeautifulSoup 实现解析二手房详情页信息并存储文件
二、知识点
Python 根底语法
Python 文件读写
BeautifulSoup 解析网页
requests 发送网络申请
三、菜鸟实战
详情页数据采集
import os.path
import platform
from base_spider import BaseSpider
from bs4 import BeautifulSoup
import pandas as pd
from tqdm import tqdm # 进度条库
class Tao365DetailSpider(BaseSpider):
# 采集 365 淘房二手房信息
list_data_file = 'tao365_list.csv' # 采集数据保留的文件
detail_data_file = 'tao365_detail.csv' # 采集数据保留的文件
url_items = [] # 采集链接数组, 取自列表文件中的每一行
detail_df = [] # 已采集的信息
def __init__(self):
# 初始化日志
self.init_log()
# 从列表文件读取期待采集的链接
list_file_path = self.fileManger.get_data_file_path(self.list_data_file)
list_df = pd.read_csv(list_file_path, encoding=self.encoding)
self.url_items = list_df.values # 初始化待采集链接数组
detail_file_path = self.fileManger.get_data_file_path(self.detail_data_file)
if os.path.isfile(detail_file_path):
# 从详情文件读取已采集的信息
self.data_file_exist = True
detail_df = pd.read_csv(detail_file_path, encoding=self.encoding)
self.detail_df = detail_df
def check_url_crawled(self, url):
# 查看以后链接是否被抓取过
if len(self.detail_df) == 0:
# 如果没有详情文件,则未抓取
return False
if url in self.detail_df.iloc[:, 1].values:
# 如果 url 在详情文件第一列中有,则示意已抓取过
self.logger.warning("url 已抓取过 %s", url)
return True
# 默认为未抓取
return False
def parse_page(self, content, url):
# 利用 BeautifulSoup 规范库,解析页面信息
soup = BeautifulSoup(content, 'lxml')
# 初始化数组
datalist = []
if soup.find("p", attrs={'class': 'line1'}):
# 题目
title = soup.find("p", attrs={'class': 'line1'}).text
# 价格
priceSplit = soup.find('span', attrs={'class': 'f48 pre bold'}).text.strip()
priceArr = priceSplit.split(' ')
price = priceArr[0] + "万"
# 每平方价格
squarePrice = soup.find('div', class_='headinfo').find('p').text.strip()
# 小区
housing = soup.find('div', attrs={'class': 'infoDetail__item long'}).find('a', class_='line1').text
area = soup.find('div', attrs={'class': 'infoDetail__item long line1'}).text
areaArr = area.split(' ')
# 地址
areaStr = ''
for area in areaArr:
area = area.replace('\n', '')
area = area.replace('地址:', '')
if area.replace('\n', '') !=' 地址:':
if len(area) > 0:
areaStr = areaStr + (area.replace('\n', ''))
ul = soup.find("ul", attrs={'class': 'detail__mainCotetn__infoBar'})
lis = ul.find_all("li")
# 屋宇户型
house_type = lis[0].text.replace('屋宇户型:', '').replace('\n','').strip()
# 建筑面积
acreage = lis[1].text.replace('建筑面积:', '').replace('\n','').strip()
# 所在楼层
level = lis[2].text.replace('所在楼层:', '').replace(' 楼层征询 ','').replace('\n', '').strip()
# 屋宇朝向
direction = lis[3].text.replace('屋宇朝向:', '').replace('\n','').strip()
# 修建年代
year = lis[5].text.replace('修建年代:', '').replace('\n','').strip()
datalist.append([title, price, squarePrice, housing, areaStr, house_type, acreage, level, direction, year])
return datalist
def crawl_data(self):
# 采集数据
for url_item in tqdm(self.url_items):
url = url_item[1]
if self.check_url_crawled(url):
continue
self.logger.debug("以后采集页面信息: %s", url)
# 发送申请, 获取数据
page_content = self.get_content_from_url(url)
# 解析数据
page_data = self.parse_page(page_content, url)
if len(page_data) == 0:
# 未获取到数据, 则持续剖析下一个
continue
# 保留数据到文件
cols = ['题目', '价格', '每平方价格', '小区', '地址', '屋宇户型', '建筑面积', '所在楼层', '屋宇朝向', '修建年代']
self.save_to_detail_file(page_data, cols)
# 避免反爬,随机休眠一段时间
self.sleep_random()
def run(self):
self.logger.debug("采集开始")
self.crawl_data()
self.logger.debug("采集完结")
if __name__ == '__main__':
print("采集 365 淘房二手房信息详情")
spider = Tao365DetailSpider()
spider.run()
print("python 版本", platform.python_version())
存储采集数据到文件
def save_to_file(self, data, cols):
# 保留到文件
file_path = self.fileManger.get_data_file_path(self.list_data_file)
# 初始化数据
frame = pd.DataFrame(data)
if not self.data_file_exist:
# 第一次写入带上列表头,原文件清空
frame.columns = cols
frame.to_csv(file_path, encoding=self.encoding, index=None)
self.data_file_exist = True # 写入后更新数据文件状态
else:
# 后续不写如列表头,追加写入
frame.to_csv(file_path, mode="a", encoding=self.encoding, index=None, header=0)
self.logger.debug("文件保留实现")
运行后果
运行截图
采集详情页运行截图
采集 365 淘房二手房信息详情
100%|██████████| 222/222 [08:37<00:00, 2.33s/it]
python 版本 3.9.10
过程已完结, 退出代码 0
后果文件
菜鸟实战,继续学习!