算技@Python爬虫-租房信息(即将过期)

Python 实战-第 1 周-练习项目03-爬取租房信息

成果展示

week01-ex03-爬取租房信息

代码

贴代码如下。同时放在 GitHub 库

#coding: utf-8
from bs4 import BeautifulSoup as bs
import requests

# CONSTANTS
FEMALE_TIP = '\xe5\xa5\xb9'
GENDER_TIP = u'\u6027\u522b\uff1a'
FEMALE = '\xe5\xa5\xb3'
MALE = '\xe7\x94\xb7'

# Source
urlFather = 'http://bj.xiaozhu.com/search-duanzufang-p1-0/'
webDataFather = requests.get(urlFather)
soupFather = bs(webDataFather.text, 'lxml')
url = (soupFather.select('#page_list > ul > li > a'))[0].get('href')
webData = requests.get(url)
soup = bs(webData.text, 'lxml')

# Raw data
title = [i.get_text() for i in soup.select('div.pho_info > h4 > em')][0]
address = [i.get_text() for i in soup.select('body > div.wrap.clearfix.con_bg > div.con_l > div.pho_info > p > span.pr5')][0]
feed_pd = [i.get_text() for i in soup.select('#pricePart > div.day_l > span')][0]
imgHouse001 = [i.get('src') for i in soup.select('#curBigImage')][0]

nameLandlord = [i.get('title') for i in soup.select('#floatRightBox > div.js_box.clearfix > div.w_240 > h6 > a')][0]
imgLandlord = [i.get('src') for i in soup.select('#floatRightBox > div.js_box.clearfix > div.member_pic > a > img')][0]
profileURL = [i.get('href') for i in soup.select('#floatRightBox > div.js_box.clearfix > div.w_240 > h6 > a')][0]
profileGet = requests.get(profileURL)
profileSoup = bs(profileGet.text, 'lxml')

if 0 == len(profileSoup.find_all("ul", class_="fd_person")):
    genderStatement = [i.get_text() for i in profileSoup.select('body > div.contentFD.clearfix > div.fd_con > \
div.fd_infor > dl > dt')][0]
    if FEMALE_TIP == genderStatement[0].encode('utf-8'):
        gender = FEMALE
    else:
        gender = MALE
else:
    gender = [i.get_text() for i in profileSoup.select('ul.fd_person > li:nth-of-type(1)')][0].strip(GENDER_TIP).encode('utf-8')

print('[Title] {}\n[Address] {}\n[Price] {}\n[Image URL(download it and open in Chrome)] {}'.format(title.encode('utf-8'), address.encode('utf-8'),
                                                                                                    feed_pd, imgHouse001))
print('[Information about the landlord]')
print('    [Name  ] {}'.format(nameLandlord.encode('utf-8')))
print('    [Gender] {}'.format(gender))
print('    [Image ] {}'.format(imgLandlord))

总结

其实这次的练习基本上没什么明显的大坑,主要是我的网络不知道为什么被小猪短租屏蔽了……并不是爬取之后被屏蔽,而是第一次想打开就没法直接打开,搬了梯子……

0. 如何得到汉字的 UTF-8 编码?

在 Terminal 中打开 python,输入代码:

ChineseChar = '她'
HER = ChineseChar.encode('utf-8')

即可在变量 HER 中存储汉字「她」的 UTF-8 编码

1. 图片打不开,怎么办?踩坑

通过检查网页(例如 http://bj.xiaozhu.com/fangzi/1657828135.html )源代码抠出来的图片对应的地址(例如http://image.xiaozhustatic1.com/00,800,533/3,0,58,5069,1800,1200,9bfff1c8.jpg )下载的图片没法直接打开?在 Debian GNU/Linux 8 (jessie) 64-bit 和 Windows 7(64-bit) 上都如此。

解决办法是:尝试把这个下载的图片拖到 Chrome 中看看,通常就能打开了。

该问题的解决要感谢同一个 QQ 群班级里的 石巨人 同学(QQ 号开头553,尾号827;)

2. 如何爬取「性别」?(踩坑

其实这不算坑。只要你看了作业提示,你估计就会想:

为什么要用条件语句 if-else?

我想到了这个疑问,于是我猜想:

或许有些房东与其他房东在「性别」项目上的展示方式不同?

我在小猪短租的北京短租首页点开了 9 位房东。幸运的是,我很快就发现了有的人与其他人不一样:有些人是没有个人页面的,像这位

观察其地址,发现她多了一个 /no.html;于是我猜想:

如果对 `http://www.xiaozhu.com/fangdong/707588338/` 发出请求,服务器相应的响应,会不会不同于服务器对于主机对 `http://www.xiaozhu.com/fangdong/1579992935/` 的请求的响应?

于是我使用了 request.get() 请求并打印了 http://www.xiaozhu.com/fangdong/707588338/ 对应的 BeautifulSoup 对象,并检查该网页的标题「该房东暂未开通房东专页」对应的代码;同时检查有个人页面的房东页面,例如这个网页的源代码,并查看其「性别」部分的代码,意外发现一个明显的区别:

有个人页面的房东页面中,有且仅有一个 `<ul class="fd_person">` 的标签,而无个人页面的房东页面中则无该标签

这意味着我们可通过搜索页面代码中该标签的有无来判断该房东是否有个人页面,从而来决定如何抓取性别。这可以通过 .find_all("tag_name", class_="value") 方法来实现第一次判断:

if 0 == len(profileSoup.find_all("ul", class_="fd_person")):
    # processing info about landlord without personal site
else:
    # processing info about landlord with personal site
  • 对于有个人页面的房东页面:只要抓取到 <li class="noborT">性别:女</li> 并使用 .get_text(),配合字符串的 .strip() 方法把「性别:」去掉,就能得到房东性别。

  • 对于没有个人页面的房东页面:观察发现 http://www.xiaozhu.com/fangdong/707588338/ 对应的页面中有一句「她的短租房列表:」,这意味着我们只要通过抓取这句话的第一个字,与「她」进行比较,即可得到房东性别。

注意在与「她」比较前,先用 string.encode('utf-8') 把待比较的汉字字符串 string 转为 UTF-8 编码。

另外,建议在程序开始前就定义好常量,以便修改和检查程序,避免出现「魔数」(Magic number)之类的问题。

从而抓取性别的代码大致如下:

# profileURL 中保存了房东个人页面对应的网址
profileGet = requests.get(profileURL)
profileSoup = bs(profileGet.text, 'lxml')

if 0 == len(profileSoup.find_all("ul", class_="fd_person")):
    genderStatement = [i.get_text() for i in profileSoup.select('body > div.contentFD.clearfix > div.fd_con > \
div.fd_infor > dl > dt')][0]
    if FEMALE_TIP == genderStatement[0].encode('utf-8'):
        gender = FEMALE
    else:
        gender = MALE

3. <BeautifulSoupObj>.select(select-para) 方法接受的参数 select-para

  • 不一定要填入 CSS Selector 的绝对路径,只要填入唯一定位信息即可(例如(部分)相对路径);唯一定位信息的获取,通过观察与分析网页源代码得到(视频+ 踩坑

  • select-para 字符串中的标签名后加入 [para-name=value],可使 <BeautifulSoupObj>.select() 把满足 [para-name="value"] 的标签都筛选出来。例如 select-para = 'img[width="90"]',那么 <BeautifulSoupObj>.select() 将筛选出所有满足 width-90<img> 标签对象(视频)

    注意:以 'img[width="90"]' 为例,这个字符串中没有任何空格,像 'img[width = "90"]' 的写法是错误的!(踩坑

4. 模拟登录(视频)

打开 Chrome 的 Inspect 选项,切换到 Network 标签页,点击下方左侧栏目中 Name 下任一(?)项,查看右侧栏的 Headers 标签页 Request Headers 中的 CookieUser-Agent,然后使用如下代码,即可在使用 requests 请求并下载网页时模拟登录:

headerInfo = {
    'Cookie': COOKIE_STRING,
    'User-Agent': USER-AGENT-STRING
}
requests.get(url, headers=headerInfo)

5. 反反爬虫技巧 001:延时(视频 + 踩坑

服务器可能通过对发送请求的频率来判断用户是否为爬虫。

我们可以通过在每次 requets.get() 之间插入延时代码来模拟人类:

import time
time.sleep(num)
# 延迟 num 秒;num 可以是浮点数

6. 反反爬虫技巧 002:从移动端代码抓取信息(视频)

有些信息在 PC 端被处理过,例如是通过 JS 代码来加载图片的,这样就可能导致直接抓取 <img> 标签可能会得到无效信息。

由于移动端代码相对 PC 端简单,我们可以通过使用 Chrome Inspect 工具栏顶部的 Toggle device mode 模拟移动端加载,从而可获取:

  1. 模拟移动端的 Cookie 与 User-Agent:用于爬虫中的 header 参数
  2. 移动端的网页代码:可能更容易找到定位图片的有效信息

7. 连续爬取连续多张网页(视频)

观察连续几张网页的地址变化规律,代入 request.get() 的参数即可

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容

  • 1 前言 作为一名合格的数据分析师,其完整的技术知识体系必须贯穿数据获取、数据存储、数据提取、数据分析、数据挖掘、...
    whenif阅读 18,070评论 45 523
  • 最近季濂走在路上,总是感觉后面有人叫他,季濂,季濂.....像是从很远的地方传来,却又存在于另外一个世界。季...
    苏见阴丶阅读 227评论 0 0
  • 我有世界上最好的妈妈 她说,爱想他就想他 不要逼迫自己 总有一天时间会帮你放下 我有世界上最好的朋友 她说,别犯贱...
    读云轩札记阅读 207评论 13 0
  • “我们会永远永远聚在一起,绝不会分离” “因为曾对夕阳承诺,不久可以再相聚” “可以再度观赏,美丽的橙色光彩……”...
    反物质仙人阅读 272评论 0 0
  • 我觉得生命中最有意义的事情是 你不知道在什么地点会遇到怎样的人 然后经历怎样的事情 或温暖 或感动 或让你懂得什...
    郡主0001阅读 168评论 0 1