有小伙伴说想拿链家二手房信息做数据分析, 让帮忙抓点数据. 并没有搞过, 网上搜了一些资料试了一下, 感觉不难可以搞, 下面小结一下.
工具
python3
python 的三方库:
- BeautifulSoup(用于解析数据)
- pandas(用于处理数据, 存储成 Excel)
- requests (用于发送请求)
三方库库的安装也比较简单, 直接使用 pip install 相应的库名 即可:
pip install pandas
pip install requests
pip install beautifulsoup4
思路
抓包基本的意思就是用代码模拟用户的请求, 然后解析相应的网页内容, 择取出需要的信息即可. 简单看了一下链家的网页结构, 是比较整齐的. 这种就是深圳二手房列表分页的链接:
- https://sz.lianjia.com/ershoufang/pg1
- https://sz.lianjia.com/ershoufang/pg2
- ...
- https://sz.lianjia.com/ershoufang/pg99
- https://sz.lianjia.com/ershoufang/pg100
可以请求一下这个链接, 然后解析返回结果, 可以抓取到每一个房子详情页面的链接. 我这边是通过正则匹配的方式解析的 (详情参考源码中 catchHouseList 函数). 解析的结果大概像这样子:
- https://sz.lianjia.com/ershoufang/105101151981.html
- https://sz.lianjia.com/ershoufang/105101102328.html
- https://sz.lianjia.com/ershoufang/105100779210.html
- https://sz.lianjia.com/ershoufang/105101254525.html
- https://sz.lianjia.com/ershoufang/105101201989.html
- https://sz.lianjia.com/ershoufang/105101262457.html
获取详情链接之后, 再请求这个详情链接, 可以获得到详情信息. 把获取到的详情信息通过 BeautifulSoup 解析, 就能得到你要的数据. 最后, 把这个数据通过 pandas 写入到 Excel 中即可 (参考 appendToXlsx 函数). 写的时候是 append 的方式.
注意的是因为大部分网站对于链接访问都有一些限制, 诸如访问太频繁了, 服务器可能认为这个请求不正常, 不会返回正确结果. 因此每次请求一个网页之后, 会等一会儿再请求下一个网页. 不至于被服务器拒绝.
- # 我这里设置为 3 秒
- time.sleep(3)
源码
下面是我的源码, 应该安装完相应的三方库, 在 python 环境运行下面的代码即可:
- import requests
- from bs4 import BeautifulSoup
- import sys
- import os
- import time
- import pandas as pd
- import numpy as np
- from parsel import Selector
- import re
- headers = {
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) ApplewebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 BIDUBrowser/8.7 Safari/537.36'
- }
- def catchHouseList(url):
- resp = requests.get(url, headers=headers, stream=True)
- if resp.status_code == 200:
- reg = re.compile('<li.*?class="clear">.*?<a.*?class="img.*?".*?href="(.*?)"')
- urls = re.findall(reg, resp.text)
- return urls
- return []
- def catchHouseDetail(url):
- resp = requests.get(url, headers=headers)
- print(url)
- if resp.status_code == 200:
- info = {}
- soup = BeautifulSoup(resp.text, 'html.parser')
- info['标题'] = soup.select('.main')[0].text
- info['总价'] = soup.select('.total')[0].text
- info['总价单位'] = soup.select('.unit')[0].text
- info['每平方售价'] = soup.select('.unitPriceValue')[0].text
- # p = soup.select('.tax')
- # info['参考总价'] = soup.select('.tax')[0].text
- info['建造时间'] = soup.select('.subInfo')[2].text
- info['小区名称'] = soup.select('.info')[0].text
- info['所在区域'] = soup.select('.info a')[0].text + ':' + soup.select('.info a')[1].text
- info['链家编号'] = str(url)[34:].rsplit('.html')[0]
- info['房屋户型'] = str(soup.select('.content')[2].select('.label')[0].next_sibling)
- info['所在楼层'] = soup.select('.content')[2].select('.label')[1].next_sibling
- info['建筑面积'] = soup.select('.content')[2].select('.label')[2].next_sibling
- info['户型结构'] = soup.select('.content')[2].select('.label')[3].next_sibling
- info['套内面积'] = soup.select('.content')[2].select('.label')[4].next_sibling
- info['建筑类型'] = soup.select('.content')[2].select('.label')[5].next_sibling
- info['房屋朝向'] = soup.select('.content')[2].select('.label')[6].next_sibling
- info['建筑结构'] = soup.select('.content')[2].select('.label')[7].next_sibling
- info['装修情况'] = soup.select('.content')[2].select('.label')[8].next_sibling
- info['梯户比例'] = soup.select('.content')[2].select('.label')[9].next_sibling
- info['供暖方式'] = soup.select('.content')[2].select('.label')[10].next_sibling
- info['配备电梯'] = soup.select('.content')[2].select('.label')[11].next_sibling
- # info['产权年限'] = str(soup.select('.content')[2].select('.label')[12].next_sibling)
- return info
- pass
- def appendToXlsx(info):
- fileName = './ 链家二手房. xlsx'
- dfNew = pd.DataFrame([info])
- if(os.path.exists(fileName)):
- sheet = pd.read_excel(fileName)
- dfOld = pd.DataFrame(sheet)
- df = pd.concat([dfOld, dfNew])
- df.to_excel(fileName)
- else:
- dfNew.to_excel(fileName)
- def catch():
- pages = ['https://sz.lianjia.com/ershoufang/pg{}/'.format(x) for x in range(1, 1001)]
- for page in pages:
- print(page)
- houseListURLs = catchHouseList(page)
- for houseDetailUrl in houseListURLs:
- try:
- info = catchHouseDetail(houseDetailUrl)
- appendToXlsx(info)
- except:
- pass
- time.sleep(3)
- pass
- if __name__ == '__main__':
- catch()
瞎墨迹
虽然技术含量并不高, 只是涉及到一些三方工具的使用. 不过实践的过程中还是遇到一些问题, 诸如对 pandas 的使用, 因为从未接触过, 就折腾了很久. 大概很多看起来很简单的东西, 真正弄起来的时候, 依旧有预料不到的问题.
其次是抓包这件事, 技术上觉得并不奇特 (当然有些网站的抓包还是有难度的), 但是小伙伴需要这个, 也许一件事情并不仅仅从技术上考量其价值.
参考资料
谷歌百度一堆, 无法判断原创性, 就懒得贴了.
来源: https://juejin.im/post/5ad6ed0451882555784e7d82