python爬虫系列(四)
目录
一、前言:
- 我们在之前学习了robots.txt文件的读取及解析,站点技术的分析以及用简单的demo演示了网页的下载过程。
- 本篇我们将以爬取安居客站点为例子,希望大家学会了爬虫后,直接用爬虫来找房子会更方便哦,再也不用久不久盯着软件看了。
- 我们本次的目标是抓取安居客的顶部信息如下:
二、Download函数的重构
-
在开始之前,我们先对之前编写的download函数做一次封装,将其封装为类。
-
这样做的目的主要是为后续的扩展做准备,程序就像滚雪球一样,我们会越滚越大的哦。
-
OK,我也不瞎逼逼了,直接上代码:
from urllib import request, error, response # 默认的重试次数 DEFAULT_RETRIES = 1 DEFAULT_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 '; class Download: # 重试次数 num_retries = 0; user_agent = None; def __init__(self, num_retries=DEFAULT_RETRIES,user_agent=DEFAULT_AGENT): self.num_retries = num_retries; self.user_agent = user_agent; def download(self,url): print('download url is %s' % url); html = None; try: rq = request.Request(url=url); rq.add_header('User-Agent',self.user_agent); rp = request.urlopen(rq); print('download over url is: %s' % rp.geturl()) html = rp.read(); except error.URLError as e: print('download error :%s' % e.reason); html = None; if self.num_retries > 0: if hasattr(e, 'code') and 500 <= e.code < 600: return self.download(url, self.num_retries - 1); pass; return html; if __name__ == '__main__': d = Download(); print(d.download('http://www.baidu.com'))
-
代码如上,我们还将重试次数,代理等抽出来作为对象的属性,后续我们的属性会更多,这次我为什么添加了代理呢?因为安居客对爬虫做了限制,不设置代理就获取不了数据的哦。
三、Spider类的编写:
-
我们再创建一个spider类来负责爬虫的控制,其获取了url后就会调用我们的download进行下载。
-
刚开始我们的类也很简单,内部目前主要实例化一个download对象来下载url,一个crawl_queue存储等待下载的url,代码如下:
from com.anjie.download import Download; class Spider: #待抓取队列 crawl_queue = []; download = None; def __init__(self): self.download = Download(); pass; #调用该函数开始让爬虫开始工作 def start_craw(self,start_url): self.crawl_queue = [start_url]; while self.crawl_queue: url = self.crawl_queue.pop(); html = self.download.download(url); print(html) if __name__=='__main__': s = Spider(); #该url,你直接用浏览器打开安居客,点击租房即可获取 s.start_craw('https://gz.zu.anjuke.com/?from=navigation');
-
Ok,我们的Spider就写好来,此时我们运行时会发现。真的下载了哦,小编没有骗你哦,不过下载后返回的html小编表示看的好郁闷。
- 不要着急,此时我们该使用神器了。
- 此时在家可以借助Chrome的调试工具来分析数据的标签,然后通过正则表达式来获取,不过实际开发过程中,这种做法肯定是行不通的。
- 接下来我们将为大家介绍两个神器:Beautiful Soup和Lxml
四、数据格式化神器:Beautiful Soup和Lxml
Beautiful Soup
- Beautiful Soup是一个可以从 HTML 或 XML 文件中提取数据的Python库,该模块可以帮助我们解析网页, 并提供定位内容的便捷接口。
Beautiful Soup使用知识补充:
- Beautiful Soup能将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,而所有对象我们可以可以归纳为以下4种:
1、Tag
- HTML 中的一个个标签,例如:
<title></title>
- 使用也是非常简单的,如我想获取html中的title标签的内容:
soup = BeautifulSoup(html) #加载html,返回一个BeautifulSoup对象 soup.title : 如此便是取里面的title标签的内容了
- 对于Tag来说,其有两个属性:
- name : 其为标签的名字,如
<a></a>
的name就是a- attrs:标签上的属性集合,返回的是一个字典,如a标签有class属性,id等。如果想获取属性的值可以:soup.a[‘class’]即可
- 注意事项:虽然这样子很好用,但是他取的都是第一个标签哦,也就是说假设你有很多 a 标签,他也会支取第一个,这样子局限性肯定很大是不。
2、NavigableString:
- 这个属性很有意思:我们前面已经获取了tag是不?我们想获取tag里的值该怎么办呢?此时我们可以使用:soup.a.string, 这样便获取了里面的值,而执行这句返回的就是一个NavigableString类型的对象了。
3、BeautifulSoup :
- BeautifulSoup 对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag,我们可以分别获取它的类型,名称,以及属性
4、Comment:
- Comment 对象是一个特殊类型的 NavigableString 对象,其实输出的内容仍然不包括注释符号,但是如果不好好处理它,可能会对我们的文本处理造成意想不到的麻烦。
- 也就是他能打印标签里的注释内容。
Beautiful Soup安装:
python3如下:pip3 install beautifulsup4 python2如下:pip install beautifulsup4
-
Ok,安装好之后,我们来试一下。
-
代码修改如下:
from com.anjie.download import Download; from bs4 import BeautifulSoup class Spider: # 待抓取队列 crawl_queue = []; download = None; def __init__(self): self.download = Download(); pass; # 调用该函数开始让爬虫开始工作 def start_craw(self, start_url): self.crawl_queue = [start_url]; while self.crawl_queue: url = self.crawl_queue.pop(); bad_html = self.download.download(url); soup = BeautifulSoup(bad_html, 'html.parser'); #执行了prettify我们的html就会变得很美丽哦,这里就不打印出来了 html = soup.prettify(); tag = soup.find_all('ul', attrs={'class': 'nav-site'}); print(tag) if __name__ == '__main__': s = Spider(); s.start_craw('https://gz.zu.anjuke.com/?from=navigation');
-
运行结果如下:
- 好开心,Ok,我们拿到了顶部导航的数据。而且BeautifulSoup返回给我们的是一个BeautifulSoup对象,其提供了非常丰富的api供我们查找相关的tag和内容。
- 如查找所有的a标签内的href的内容:
for link in soup.find_all(‘a’): print(link.get(‘href’))
- 虽然Beautiful Soup已经很强大了,但是我想说,我更喜欢lxml,因为它支持xpath语法。
Lxml
- Lxml 是基于 libxml2 这一XML解析库的Python封装。 该模块使用C语言编写,解析速度比Beautiful Soup更快,最新版本的lxml支持CPython2.6至3.6的版本。
- Lxml也是唯一支持解析XMl的库哦。
- 其实我安装时感觉挺简单的,虽然网上说安装比较复杂。
- 我一不小心执行了:pip3 install lxml 就搞定了
Lxml常用方法及属性详解:
- 1、fromstring(html, base_url=None, parser=None, **kwargs) :将字符型html文档转换为节点树或文档树
- 2、 tostring(doc, pretty_print=False, include_meta_content_type=False, encoding=None, method=“html”, with_tail=True, doctype=None) : 将节点树或文档树序列化为字符型
- 3、base_url : 文档url
- 4、head : 标签部分
- 5、body : 标签部分
- 6、forms : 返回全部form列表
- 7、label : 元素的label标签
- 8、classes : class属性值的集合
- 9、drop_tag(self) : 移除标签,但不移除其子标签和text文本,将其合并到父节点
- 10、drop_tree(self) : 移除节点树(包含子节点和text),但不移除它的tail文本,将其合并到父节点或前一个兄弟节点
- 11、find_class(self, class_name) : 根据class属性值查找节点元素
- 12、get_element_by_id(self, rel) : 根据id属性值查找节点元素
- 13、set(self, key, value=None) :设置节点元素的属性
- 14、text_content(self) : 返回其后代节点与其自身的全部text内容
-
示例代码如下:
from com.anjie.download import Download; from lxml import html as lhtml; class Spider: # 待抓取队列 crawl_queue = []; download = None; def __init__(self): self.download = Download(); pass; # 调用该函数开始让爬虫开始工作 def start_craw(self, start_url): self.crawl_queue = [start_url]; while self.crawl_queue: url = self.crawl_queue.pop(); bad_html = self.download.download(url); bad_html = bad_html.decode('utf-8') root = lhtml.fromstring(bad_html); result = root.xpath('//div[@class="topbar "]//ul/li/*') for s in result: print(s.text) if __name__ == '__main__': s = Spider(); s.start_craw('https://gz.zu.anjuke.com/?from=navigation');
-
输出为:
download url is https://gz.zu.anjuke.com/?from=navigation download over url is: https://gz.zu.anjuke.com/?from=navigation 首 页 新 房 二手房 租 房 商铺写字楼 海外地产 楼讯 房 价 问 答
-
Lxml不仅与Beautiful Soup一样支持api获取数据,还支持xpath和css抽取器。
-
由于其功能强大,后面我们将单独抽出一篇来讲解lxml的使用,这里我们只需要知道有这么个东西即可。