详解Python 采用 requests + Beautiful Soup 爬取房天下新楼盘推荐

最近一直在关注Python写爬虫相关的知识,尝试了采用requests + Beautiful Soup来爬取房天下(原搜房网)的推荐新楼盘。html

不用不知道,一用发现有惊喜也有惊吓,本文就一同记录下惊喜和踩的一些乱码的坑。
python


首先,以为Beautiful soup解析网页更加符合人类的常规思惟,比使用正则表达式(python中的re库)更容易理解。 同时关于requests遇到了中文字符和特殊字符解码的问题。本文都将给于深刻的解说。正则表达式


软件环境bash

Python    : 3.6.0   app

PyCharm: Community 2017.2 ide

库1 : requests测试

库2 : beautifulsoupui



Requests知识概要this


Requests 是用Python语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库。它比 urllib 更加方便,能够节约咱们大量的工做,彻底知足 HTTP 测试需求。编码

彻底支持Python3哦


1. 安装requests 

   能够采用pip安装requests,具体代码是:

pip install requests

2. 简单例子

   下面例子中是几个经常使用的属性,response.text能够获得html的源代码,response.encoding默认为ISO-8859-1,此编码针对英文没有问题,若是咱们的网页中带有中文,将会引发乱码的问题。后面有解决方案。

import requests
response = requests.get("http://sh.fang.com/") #获取一个Http请求
print(response.encoding)          #当前编码,默认为 ISO-8859-1
print(response.apparent_encoding) #当前网页的内容的实际编码
print(response.content)  #content返回的是bytes型的原始数据
print(response.text)     #text返回的是处理过的Unicode型的数据



Beautiful Soup简要知识

1. Beautiful Soup 是一个很是流行的 Python 模块。 该模块能够解析网页, 并

提供定位 内 容的便捷接 口 。 若是你尚未安装该模块, 可使用下面的命令

安装其最新版本:

pip install beautifulsoup4

使用 Beautiful Soup 的第一步是将下载的 HTML 内容解析为 soup 文档 。


2. 如何引用Beautiful Soup

from bs4 import BeautifulSoup


3. 一个简单例子

from bs4 import BeautifulSoup


html = "<ul class='country'><li>中国</li><li>美国</li></ul>"
# 解析html而后获得一个soup文档
soup = BeautifulSoup(html,'html.parser')
html = soup.prettify()
ul = soup.find('ul',attrs={'class':'country'})

#下面代码只返回一个匹配的元素
print(ul.find('li'))     # returns the first match element

#下面代码返回又有匹配的元素
for countryname in ul.find_all('li'):
    print(countryname)


实战爬取房天下推荐新楼盘


  1. 在Chrome中打开sh.fang.com地址,按F12观察新盘推荐tab的网页源代码结构


    主要结构是: 顶层为一个名为ti011的div,下面有四个class为tenrtd的div用于四个楼盘的现实。每一个楼盘下面有一个class = "text1"的div存储了楼盘名称,另外一个class = "text2"的存储了楼盘的价格。


    image.png

     

     2. 初版代码完成以下,可是发现有一个中文乱码的问题

from bs4 import BeautifulSoup
import requests
rep = requests.get("http://sh.fang.com/")
html = rep.text
soup = BeautifulSoup(html, 'html.parser')
#获取顶层 新盘推荐 的整个div
div = soup.find('div',attrs={'id':'ti011'})
#获取四个楼盘的div,更具他们的class = "tenrtd"
for house in div.find_all('div', attrs={'class': 'tenrtd'}):
    
    # 根据class="text1"获取存储楼盘标题的div
    titleDiv = house.find('div', attrs={'class': 'text1'})
    title = titleDiv.find('a').text
    # 根据class="text2"获取存储楼盘价格的div
    priceDiv = house.find('div', attrs={'class': 'text2'})
    price = priceDiv.find('b').text
    print(title, " ", price)

 

输出的结果尽然是这样, Why?

 Öнðº£ÌÄÍå     48000Ôª/©O 
 »ªÒêÒÝÆ·À½Íå     43057Ôª/©O 
 Öйú¹é¹È´´¿ÍSOHO     ¼Û¸ñ´ý¶¨ 
 ÐÂÎ÷ÌÁ¿×ȸ³Ç     14000Ôª/©O


   3. 研究中文乱码问题

    中文乱码也算是requests常见的一个问题,为何会这样的呢,看bs本身的文档描述

Encodings
When you receive a response, Requests makes a guess at the encoding to use for decoding the response 
when you access the Response.text attribute. Requests will first check for an encoding in the HTTP 
header, and if none is present, will use chardet to attempt to guess the encoding.

The only time Requests will not do this is if no explicit charset is present in the HTTP headersand 
the Content-Type header contains text. In this situation, RFC 2616 specifies that the default charset 
must be ISO-8859-1. Requests follows the specification in this case. If you require a different encoding, 
you can manually set the Response.encoding property, or use the rawResponse.content.

    其实重要的也就是若是没有在requests的header部分里面指定encoding的话,那么默认采用ISO-8859-1这个编码去解码response.content里面的字节数据。ISO-8859-1针对英文是没有问题的,可是针对中文就不行了。


    解决思路固然就是换encoding,可是咱们应该用什么编码呢?下面这个代码能够看到网页的实际encoding,下面代码将输出:GB2312 ,因此咱们采用GB2312来解码咱们的数据。

print(rep.apparent_encoding)


    4.换编码解决中文字符

    通过上面的研究,咱们修订代码对response设定encoding = "GB2312"

rep.encoding = "GB2312"

   运行后结果以下:

  中金海棠湾     48000元/�O 
 华谊逸品澜湾     43057元/�O 
 中国归谷创客SOHO     价格待定 
 新西塘孔雀城     14000元/�O

   发现代码显示的结果中又乱码了,不该该啊,这又是为何呢? 下面接着研究。。。


   5. 研究解决特殊字符乱码问题

       引发乱码的缘由估计就是在字符集中找不到特定的字符,好比这个㎡。是否是GB2312这个字符集不够全面呢?带着这个疑问去查阅相关的资料关于中文的几个编码:

  • GB2312

GB 2312 或 GB 2312-80 是中国国家标准简体中文字符集,全称《信息交换用汉字编码字符集·基本集》,又称 GB 0,由中国国家标准总局发布,1981 年 5 月 1 日实施。GB 2312 编码通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎全部的中文系统和国际化的软件都支持 GB 2312。GB 2312 标准共收录 6763 个汉字,其中一级汉字 3755 个,二级汉字 3008 个;同时收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的 682 个字符。GB 2312 的出现,基本知足了汉字的计算机处理须要,它所收录的汉字已经覆盖中国大陆99.75% 的使用频率。对于人名、古汉语等方面出现的罕用字,GB 2312 不能处理,这致使了后来 GBK 及 GB 18030 汉字字符集的出现


       

  • GBK

GBK 即汉字内码扩展规范,K 为汉语拼音 Kuo Zhan(扩展)中“扩”字的声母。英文全称 Chinese Internal Code Specification。GBK 共收入 21886 个汉字和图形符号,包括:GB 2312 中的所有汉字、非汉字符号。BIG5 中的所有汉字。与 ISO 10646 相应的国家标准 GB 13000 中的其它 CJK 汉字,以上合计 20902 个汉字。其它汉字、部首、符号,共计 984 个。GBK 向下与 GB 2312 彻底兼容,向上支持 ISO 10646 国际标准,在前者向后者过渡过程当中起到的承上启下的做用。GBK 采用双字节表示,整体编码范围为 8140-FEFE 之间,首字节在 81-FE 之间,尾字节在 40-FE 之间,剔除 XX7F 一条线


  • GB18030

GB 18030,全称:国家标准 GB 18030-2005《信息技术中文编码字符集》,是×××现时最新的内码字集,是 GB 18030-2000《信息技术信息交换用汉字编码字符集基本集的扩充》的修订版。GB 18030 与 GB 2312-1980 和 GBK 兼容,共收录汉字70244个。与 UTF-8 相同,采用多字节编码,每一个字能够由 1 个、2 个或 4 个字节组成。编码空间庞大,最多可定义 161 万个字符。支持中国国内少数民族的文字,不须要动用造字区。汉字收录范围包含繁体汉字以及日韩汉字


    从上文中能够简要的得出GB 2312 过期标准、GBK 微软标准、GB 18030 国家标准,字符个数方面:GB 18030 > GBK > GB2312


因此咱们决定采用 GB18030来解码咱们的数据,代码改动以下:

rep.encoding = "gb18030"



附上完整的代码


from bs4 import BeautifulSoup
import requests

rep = requests.get("http://sh.fang.com/")
rep.encoding = "gb18030"
html = rep.text
soup = BeautifulSoup(html, 'html.parser')

#获取顶层 新盘推荐 的整个div
div = soup.find('div',attrs={'id':'ti011'})

#获取四个楼盘的div,更具他们的class = "tenrtd"
for house in div.find_all('div', attrs={'class': 'tenrtd'}):
    # 根据class="text1"获取存储楼盘标题的div
    titleDiv = house.find('div', attrs={'class': 'text1'})
    title = titleDiv.find('a').text
    # 根据class="text2"获取存储楼盘价格的div
    priceDiv = house.find('div', attrs={'class': 'text2'})
    price = priceDiv.find('b').text
    print(title, " ", price)


输出结果:

 中金海棠湾     48000元/㎡ 
 华谊逸品澜湾     43057元/㎡ 
 中国归谷创客SOHO     价格待定 
 新西塘孔雀城     14000元/㎡


问题解决了,关键知识点总结:

  1. 能够采用requests库来获取网页html

  2. 采用Beautiful soup基于html构建一个soup文档,而后用find 或者 find_all方法查询本身须要的html节点

  3. 根据目标网页的内容来更改response.encoding从而解决乱码问题

相关文章
相关标签/搜索