当前位置: 首页 > 编程日记 > 正文

如何高效地爬取链家的房源信息(一)

Python实现的链家网站的爬虫第一部分。


在之前的文章,以链家成都站为例,分析过链家网站数据的爬取,文章如下:

干货!链家二手房数据抓取及内容解析要点


但是,当时没有根据分析,将爬取实现。


本系列文将以链家南京站为例,使用Python实现链家二手房源信息的爬虫,将数据爬取,并存入数据库中,以便使用。


本文是第一部分,是整个爬取的基础,包括爬取逻辑、伪装正常访问、数据库设计及封装、区域URL爬取四个部分。


01

爬取逻辑


本文爬取的地区站虽与之前分析的地区站不同,但二者的结构是一样的,之前分析的成果可以直接套用。


根据之前的分析成果,得到爬取流程如下:

第一步,找到爬取站点的地址,这里爬取的是南京站,为https://nj.lianjia.com/。

第二步,从二手房查询页面获取大区信息,以便后续的查询。

这样的好处是可以分区查询,避免单次数据太多,链家服务器无法返回全部内容,最终导致数据不全。

第二步,根据分区信息,获取小区信息,存数据库,后续爬取操作,均以小区信息为起点。

第三步,根据各个小区信息,获取该小区的所有在售房源信息,存数据库。

第四步,根据各个小区信息,获取该小区的所有成交房源信息,存数据库。


确定了爬取流程,也就确定了程序的基本框架,接下来我们还需要准备相关Python库,数据库——sqlite3,以及分析网页库——BeautifulSoup。后者的安装参考:

Windows下Python 3.6 安装BeautifulSoup库


02


伪装正常访问


为避免被服务器发现爬虫行为,通常需要准备一批User Agents,这里收集了一些UA,可以直接拿去使用:

hds = [{'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}, \

       {'User-Agent': 'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11'}, \

       {'User-Agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)'}, \

       {'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:34.0) Gecko/20100101 Firefox/34.0'}, \

       {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/44.0.2403.89 Chrome/44.0.2403.89 Safari/537.36'}, \

       {'User-Agent': 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'}, \

       {'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'}, \

       {'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0'}, \

       {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'}, \

       {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'}, \

       {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11'}, \

       {'User-Agent': 'Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11'}, \

       {'User-Agent': 'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11'}]


03


数据库设计及封装


由于房源数据量不小,使用文本方式保存明显不便,因此,我们采用SQLite来进行数据的存储。这里,设计三个数据库,来保存不同的信息:

lianjia-xq.db,用来存储小区信息,需要存储URL、小区名称、小区区域及建设年代等信息。


lianjia-cj.db,用来存储小区成交二手房的信息,需要存储链接、小区名称、户型、面积、朝向、装修、电梯、签约时间、签约总价、楼层、年代楼型、来源、签约单价、税费、地铁、挂牌价、成交周期等信息。


lianjia-zs.db用来存储小区在售二手房的信息,需要存储链接、房子描述、小区名称、户型、面积、朝向、装修、电梯、楼层年代楼型、区域、关注、带看、发布时间、税费、地铁、限制、挂牌价、挂牌单价等信息。


这样,基本上把网站上的描述点都给提取出来了。


同时,我们对数据库的操作进行封装以便操作,直接参考网上的代码,并适当修改,这里给出代码:

class SQLiteWraper(object):

"""

数据库的一个小封装,更好的处理多线程写入

"""

def __init__(self, path, command='', *args, **kwargs):

self.lock = threading.RLock()  # 锁

self.path = path  # 数据库连接参数

if command != '':

conn = self.get_conn()

cu = conn.cursor()

cu.execute(command)


def get_conn(self):

conn = sqlite3.connect(self.path)  # ,check_same_thread=False)

conn.text_factory = str

return conn


def conn_close(self, conn=None):

conn.close()


def conn_trans(func):

def connection(self, *args, **kwargs):

self.lock.acquire()

conn = self.get_conn()

kwargs['conn'] = conn

rs = func(self, *args, **kwargs)

self.conn_close(conn)

self.lock.release()

return rs


return connection


@conn_trans

def execute(self, command, method_flag=0, conn=None):

cu = conn.cursor()

try:

if not method_flag:

cu.execute(command)

else:

cu.execute(command[0], command[1])

conn.commit()

except sqlite3.IntegrityError as e:

# print e

return -1

except Exception as e:

print(e)

return -2

return 0


@conn_trans

def fetchall(self, command="select name from xiaoqu", conn=None):

cu = conn.cursor()

lists = []

try:

cu.execute(command)

lists = cu.fetchall()

except Exception as e:

print(e)

pass

return lists


同时,封装几个具体的操作。

生成小区数据库插入操作命令:

def gen_xiaoqu_insert_command(info_dict):

"""

生成小区数据库插入命令

"""

info_list = [ u'url',u'小区名称', u'大区域', u'小区域', u'建造时间']

t = []

for il in info_list:

if il in info_dict:

t.append(info_dict[il])

else:

t.append('')

t = tuple(t)

command = (r"insert into xiaoqu values(?,?,?,?,?)", t) #?,

return command


生成成交记录数据库插入操作命令:

def gen_chengjiao_insert_command(info_dict):

"""

生成成交记录数据库插入命令

"""

info_list = [u'链接',u'小区名称',u'户型',u'面积',u'朝向',u'装修',u'电梯',u'签约时间',u'签约总价',u'楼层',u'年代楼型',u'来源',u'签约单价',u'税费',u'地铁',u'挂牌价',u'成交周期']

t = []

for il in info_list:

if il in info_dict:

t.append(info_dict[il])

else:

t.append('')

t = tuple(t)

command = (r"insert into chengjiao values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", t)

return command


生成在售记录数据库插入操作命令:

def gen_zaishou_insert_command(info_dict):

"""

生成在售记录数据库插入命令

"""

info_list = [u'链接',u'房子描述',u'小区名称',u'户型',u'面积',u'朝向',u'装修',u'电梯',u'楼层年代楼型',u'区域',u'关注',u'带看',u'发布时间',u'税费',u'地铁',u'限制',u'挂牌价',u'挂牌单价']

t = []

for il in info_list:

if il in info_dict:

t.append(info_dict[il])

else:

t.append('')

t = tuple(t)

command = (r"insert into zaishou values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", t)

return command


当然,数据库表需要创建:

command = "create table if not exists xiaoqu (url TEXT primary key UNIQUE,name TEXT, regionb TEXT, regions TEXT, year TEXT)"#

db_xq = SQLiteWraper('lianjia-xq.db', command)


command = "create table if not exists zaishou (href TEXT primary key UNIQUE, detail TEXT,xiaoqu TEXT, style TEXT, area TEXT, orientation TEXT, zhuangxiu TEXT, dianti TEXT, loucenniandai TEXT, quyu TEXT, guanzhu TEXT, daikan TEXT, fabushijian TEXT,shuifei TEXT,subway TEXT,xianzhi TEXT, total_price TEXT, unit_price TEXT)"

db_zs = SQLiteWraper('lianjia-zs.db', command)


command = "create table if not exists chengjiao (href TEXT primary key UNIQUE, name TEXT, style TEXT, area TEXT, orientation TEXT, zhuangxiu TEXT, dianti TEXT, sign_time TEXT, total_price TEXT, loucen TEXT, year TEXT,source TEXT, unit_price TEXT,shuifei TEXT, subway TEXT, guapaiprice TEXT, cycletime TEXT)"

db_cj = SQLiteWraper('lianjia-cj.db', command)


基础准备好了,接下来就是具体的爬取了。


04


区域URL爬取及异常处理


爬取大区域的URL:

def get_qu_url_spider():

"""

爬取大区信息

"""

url = u"https://nj.lianjia.com/xiaoqu/"

try:

req = urllib.request.Request(url, headers=hds[random.randint(0, len(hds) - 1)])

source_code = urllib.request.urlopen(req, timeout=5).read()

plain_text = source_code.decode('utf-8');

soup = BeautifulSoup(plain_text,"html.parser")

except (urllib.request.HTTPError, urllib.request.URLError) as e:

print(e)

return

except Exception as e:

print(e)

return


d=soup.find('div', {'data-role':"ershoufang"}).findAll('a');

for item in d:

href=item['href'];

region = item.contents[0];

fullhref=u"https://nj.lianjia.com"+href;

print(region+fullhref);

regions.append(region)

regionurls.append(fullhref)


爬取过程中如果异常,写入异常日志:

def exception_write(fun_name,url):

"""

写入异常信息到日志

"""

lock.acquire()

f = open('log.txt','a')

line="%s %s\n" % (fun_name,url)

f.write(line)

f.close()

lock.release()


爬取的URL不需要存入数据库,直接存到一个列表即可,然后遍历,获取各个大区域的小区信息。




在接下来将说明如何爬取小区信息、在售二手房信息、历史成交二手房信息,敬请期待。

640?wx_fmt=jpeg

长按进行关注。

相关文章:

HDU5886 Tower Defence 【两遍树形dp】【最长链预处理】

题意:N个点的一棵带权树。切掉某条边的价值为切后两树直径中的最大值。求各个边切掉后的价值和(共N-1项)。 解法一: 强行两遍dp,思路繁琐,维护东西较多: dis表示以i为根的子树的直径&#xff0c…

NPOI读取Excel数据应用

NPOI 是 POI 项目的 .NET 版本。使用 NPOI 你就可以在没有安装 Office 或者相应环境的机器上对 WORD/EXCEL 文档进行读写。NPOI是构建在POI 3.x版本之上的,它可以在没有安装Office的情况下对Word/Excel文档进行读写操作。 需求:根据excel表格提供的SVN相…

pod setup慢的解决方法

最近使用pod setup更新CocoaPods本地检索库,无奈只有10几k,还中途报错。最终通过以下步骤,完成更新。 1.手动下载Specs检索库 执行pod setup后,实质是从github上clone检索库(https://github.com/CocoaPods/Specs&…

如何高效地爬取链家的房源信息(二)

“Python实现的链家网站的爬虫第二部分。”本系列文将以链家南京站为例,使用Python实现链家二手房源信息的爬虫,将数据爬取,并存入数据库中,以便使用。本系列第一部分:如何高效地爬取链家的房源信息(一&…

C#实现HttpPost提交文件

先建立一个WebApplication Web.config <?xml version"1.0" encoding"utf-8"?><configuration><system.web><!--<globalization requestEncoding"gb2312" responseEncoding"gb2312" fileEncoding"gb231…

16年10月18号2th运算符与流程结构

---恢复内容开始--- 2th: 一&#xff1a;运算符 算数运算符 - * / %取余 9%30 自增 --自减 关系运算符 < < > > 全等于 !不等于 逻辑运算符 & | &#xff01;非 ^异或 &&短路与 || 短路或 赋值…

通用的排序按钮

排序按钮&#xff0c;使用Core Graphic绘制&#xff0c;可以指定颜色、大小、字体等&#xff1a; 使用场景如下&#xff1a; 1.使用方法 下载demo代码。将HYRankView.h和HYRankView.m代码拖入工程。 然后使用如下代码&#xff0c;即可快速添加一个名称为价格的排序按钮 HYR…

如何高效地爬取链家的房源信息(三)

“Python实现的链家网站的爬虫第三部分。”本系列文将以链家南京站为例&#xff0c;使用Python实现链家二手房源信息的爬虫&#xff0c;将数据爬取&#xff0c;并存入数据库中&#xff0c;以便使用。本系列第一部分为基础&#xff1a;如何高效地爬取链家的房源信息&#xff08;…

Swift学习总结【持续更新】

1、 try、try?、try!的区别&#xff1a; try&#xff1a;需要用catch捕捉异常&#xff0c;如&#xff1a; do {let data try encoder.encode(item) try data.write(to: dataFilePath(), options: .atomic)} catch {print("Error encoding item array:\(error.localize…

svn清理失败且乱码 问题解决(转)

由于昨天在网络不好的状态下频繁尝试svn更新&#xff0c;导致今天svn更新时出现&#xff1a;清理失败且乱码的情况如下&#xff1a; 以下是解决方案&#xff1a;1.下载sqlite3.exe ,地址为&#xff1a;http://download.csdn.net/detail/whyzzj/63465292.在D盘建立文件夹 tools …

UI学习第二篇 (控件)

UIbutton 也是一个控件&#xff0c;它属于UIControl 用的最多的就是事件响应 1. //创建按钮对象 UIButton * _botton [UIButton buttonWithType:UIButtonTypeCustom]; //设置标题 [_botton setTitle:"按住说话" forstate:UIControlStateNormal]; [_botton setTitle:…

如何高效地爬取链家的房源信息(四)

“Python实现的链家网站的爬虫第四部分&#xff0c;最后一部分。”本系列文将以链家南京站为例&#xff0c;使用Python实现链家二手房源信息的爬虫&#xff0c;将数据爬取&#xff0c;并存入数据库中&#xff0c;以便使用。本系列第一部分为基础&#xff1a;如何高效地爬取链家…

Quartz2D在项目中的实际使用

还记得大学刚学iOS那会&#xff0c;从学校图书馆借了本iOS开发的书&#xff0c;有一章节介绍了Quartz2D&#xff0c;当时看得一头雾水&#xff0c;感觉这画画线&#xff0c;画画圆有什么用呢&#x1f914;️&#xff1f;工作一段时间后&#xff0c;遇到了一些需求&#xff0c;终…

区别:电感、磁珠和零欧电阻的作用

转载&#xff1a;http://www.cntronics.com/sensor-art/80022840 【导读】电感、磁珠和零欧电阻在电路中是常见的身影。对于这三者在电路中的作用及它们之间的区别&#xff0c;相信还有很多工程师不是很清楚。不过没关系&#xff0c;小编在此为大家奉上一篇关于电感、磁珠和零欧…

【转载】Linux下安装、配置、启动Apache

原文地址:http://www.cnblogs.com/zhuque/archive/2012/11/03/2763352.html 安装Apache前准备&#xff1a; 1、检查该环境中是否已经存在httpd服务的配置文件&#xff0c;默认存储路径&#xff1a;/etc/httpd/httpd.conf&#xff08;这是centos预装的Apache的一个ent版本&#…

MIME格式解析

“ 本文介绍常见的MIME数据格式。”在协议还原中&#xff0c;不可避免地&#xff0c;经常会在各类协议内容中碰到MIME格式&#xff0c;例如标准邮件协议、HTTP协议。那么&#xff0c;什么是MIME呢&#xff1f;MIME是英文Multipurpose Internet Mail Extensions的缩写&#xff0…

AngularJs--过滤器(filter)

过滤器&#xff08;filter&#xff09;正如其名&#xff0c;作用就是接收一个输入&#xff0c;通过某个规则进行处理&#xff0c;然后返回处理后的结果。主要用在数据的格式化上&#xff0c;例如获取一个数组中的子集&#xff0c;对数组中的元素进行排序等。ng内置了一些过滤器…

【一步步学小程序】1.创建项目以及TabBar

1.创建项目 如图&#xff0c;创建项目&#xff0c;输入项目名称、选择目录&#xff0c;AppID是唯一标识&#xff0c;我们可以先点如图红框内的测试号&#xff0c;自动生成一个AppID&#xff0c;然后点新建即创建完一个新项目。 2.创建3个页面 确保如图左上角的编译器按钮是…

Yii在window下的安装方法

首先&#xff0c;在http://www.yiichina.com/上下载yii 然后&#xff0c;配置系统环境变量&#xff0c;在win8下&#xff0c;按winx&#xff0c;找到系统->高级系统设置->环境变量->path 把php的运行环境&#xff0c;加入到环境变量中&#xff0c;以分号隔开。如&…

从新手到入门,如何进入协议分析的世界

“ 协议分析与还原自学及入门指南。”有部分朋友给我发消息&#xff0c;说对协议还原很感兴趣&#xff0c;但苦于没人指导&#xff0c;希望得到我的帮助&#xff0c;问我如何进行协议分析的学习。这篇文章从初学者的角度&#xff0c;编列了一个学习指南&#xff0c;希望能对协议…

C# 学习笔记01

想写一个app可以访问数据库&#xff0c;实现对数据库的查询&#xff0c;修改等&#xff0c;突然发现知识实在有限&#xff0c;故选择C#来实现此app。 使用简单的三层架构来作为此app的架构。表现层&#xff08;UI&#xff09;、业务逻辑层&#xff08;BLL&#xff09;、数据访问…

转载 iOS js oc相互调用(JavaScriptCore) --iOS调用js

iOS js oc相互调用&#xff08;JavaScriptCore&#xff09; 从iOS7开始 苹果公布了JavaScriptCore.framework 它使得JS与OC的交互更加方便了。 下面我们就简单了解一下这个框架 首先我导入framework 方法如下 点击Linked Frameworks and Libraries 的添加后 选择 JavaScriptCor…

【一步步学小程序】2.列表展示

我们上一节已经创建了一个可以点击切换的tabbar。这节我们开始正式敲代码&#xff0c;在首页上展示一个可以上下滚动的课程列表&#xff1a; 首先打开上一节的pages/home/homeMain/homeMain.wxml文件&#xff0c;布局相关代码都会在此文件中&#xff0c;小程序的布局方式类似H…

git分支的合并

原文&#xff1a; http://gitbook.liuhui998.com/3_3.html http://gitbook.liuhui998.com/5_3.html 一、如何分支的合并在git中&#xff0c;可以使用git merge 和git rebase两个命令来进行分支的合并。git merge 和git rebase在大体上都差不多&#xff0c;下文主要以git merg…

【一步步学小程序】3. 使用自定义组件(component)

上一节创建了一个包含多个课程数据的列表。这一节我们用自定义组件&#xff08;component&#xff09;&#xff0c;来优化列表页面&#xff0c;即如图&#xff0c;我们把每个课程单元格封装为组件。 使用组件的好处&#xff1a; 自定义组件可以在不同的页面中重复使用将复杂…

《lua程序设计(第二版)》学习笔记(五)-- 函数基础

-- 第 5 章 函数-- 一种对语句和表达式进行抽象的主要机制 print(os.date()); -- 打印日期 Sun Apr 20 12:44:46 2014 -- 一看到sun&#xff0c;感慨广州没有晴天 -- 函数没有参数也要括号 -- 特殊情况:只有一个参数的时候, 并且参数一个string&#xff0f;table构造…

HTTP协议中的chunked编码解析

“ HTTP协议中的chunked传输编码全接触。”在HTTP协议中&#xff0c;服务器发往客户端的数据中&#xff0c;通常都包括HTTP头和HTTP体&#xff0c;当存在HTTP体的时候&#xff0c;HTTP体的长度通常是由HTTP头内的“Content-Length”字段确定。就像下图&#xff1a;不过&#xf…

html-css实例

<!DOCTYPE html> <html><head><meta charset"utf-8" /><title>求签</title><style type"text/css">*{margin: 0px;padding: 0px;font-family: "微软雅黑",arial,sans-serif;}body{background: url(im…

【Swift】变量/常量/类型总结

1、变量&#xff08;Variable&#xff09; 变量&#xff0c;可以理解为存放某一类型的值的容器&#xff0c;如&#xff1a; var count:Int var shouldRemind:BOOL var text:String var list:[ChecklistItem]一个变量的数据类型&#xff0c;决定了它能存放什么类型的数据。有些…

ODBC更新记录集提示”记录集为只读“

创建的ODBC应用程序默认的记录集不具有只读属性&#xff0c;但是再更新记录表时会提示”记录集为只读“&#xff0c;这是为什么呢&#xff1f; 今天看书找到了答案&#xff1a; 因为MFC中的数据库类不支持需要连接两个或者多个表的记录集更新&#xff0c;如果选择数据源的时候选…