轻松搞定python爬虫,秒懂数据抓取。
我们需要让爬虫从每个网页中抽取一些数据,然后实现某些事情,这种做法被称为数据抓取。
分析网页
查看网页源代码,使用Firebug Lite扩展,Firebug是Joe Hewitt开发的一套与Firefox集成在一起的功能强大的web开发工具,可以实时编辑、调试和监测任何页面的CSS、HTML和JavaScript。在这里用于网页源代码的查看。
安装Firebug Lite,下载Firebug Lite的包,然后再浏览器中安装这个插件。
三种网页抓取的方法
正则表达式、BeatifulSoup模板、强大的lxml模块
正则表达式
def download(url,user_agent='wswp',proxy=None,num_retries=2): print 'Downloading:',url headers={'User-agent':user_agent} request=urllib2.Request(url,headers=headers) opener=urllib2.build_opener() if opener: proxy_params={urlparse.urlparse(url).scheme:proxy} opener.add_handler(urllib2.ProxyHandler(proxy_params)) try: html=urllib2.urlopen(request).read() except urllib2.URLError as e: print 'Download:' ,e.reason html=None if num_retries>0: if hasattr(e,'code') and 500 <=e.code<600: return download(url,num_retries-1) return html def get_links(html): webpage_regx=re.compile('<a[^>]+href=["\'](.*?)["\']',re.IGNORECASE) # webpage_regx=re.compile(,re.IGNORECASE) link_list1=webpage_regx.findall(html) link_list2=[] for link in link_list1: if re.search('/view/',link): link_list2.append(link) return link_list2 import re url='http://example.webscraping.com/view/United-Kingdom-239' html=download(url) for link in get_links(html): link = urlparse.urljoin(url, link) areas=download(link) # print areas #匹配国家面积 context=re.findall(r'<td class="w2p_fw">(.*?)</td>',areas)[1] print context
运行结果:
正则表达式提供了抓取数据的快捷方式,但是该方法过于脆弱,容易在网页更新后出现问题。
Beautful Soup
Beautful Soup是一个非常流行的Python模块。该模块可以解析网页,并提供定位内容的便捷接口。
安装
pip install beautifulsoup4 --user
使用第一步:将已经下载的HTML内容解析为soup文档。
使用find或者find_all方法获取.
Lxml
基于libxml2这一XML解析库的Python封装.该模块使用C编写,解析速度更快.
第一步:将有可能步合法的HTML解析为统一格式.
import lxml.html broken_html='<ul class=country><li>Area<li>Population</ul>' tree=lxml.html.fromstring(broken_html) fixed_html=lxml.html.tostring(tree,pretty_print=True) print fixed_html """ <ul class="country"> <li>Area</li> <li>Population</li> </ul> """
测试三种方法的性能
import re import urllib2 import urlparse from bs4 import BeautifulSoup import lxml.html import time # # # #获取网页内容 def download(url,user_agent='wswp',proxy=None,num_retries=2): print 'Downloading:',url headers={'User-agent':user_agent} request=urllib2.Request(url,headers=headers) opener=urllib2.build_opener() if opener: proxy_params={urlparse.urlparse(url).scheme:proxy} opener.add_handler(urllib2.ProxyHandler(proxy_params)) try: html=urllib2.urlopen(request).read() except urllib2.URLError as e: print 'Download:' ,e.reason html=None if num_retries>0: if hasattr(e,'code') and 500 <=e.code<600: return download(url,num_retries-1) return html #使用正则表达式匹配 def re_scraper(html): results={} results['area']=re.search('<tr id="places_area__row">.*?<td class="w2p_fw">(.*?)</td>',html).groups()[0] return results #使用BeautifulSoup匹配 def bs_scraper(html): soup=BeautifulSoup(html) results={} results['area']=soup.find('table').find('tr',id='places_area__row').find('td', class_='w2p_fw').string return results #使用cssselect选择器匹配 def lxml_scraper(html): tree=lxml.html.fromstring(html) results={} conf=tree.cssselect('table > tr#places_area__row > td.w2p_fw')[0].text_content() results['area']=conf return results #计算获取时间 #每个网站爬取的次数 NUM_ITERATIONS=1000 html=download('http://example.webscraping.com/places/default/view/Afghanistan-1') for name,scraper in [('Re',re_scraper),('Bs',bs_scraper),('Lxml',lxml_scraper)]: #开始的时间 start=time.time() for i in range(NUM_ITERATIONS): if scraper==re_scraper: #默认情况下,正则表达式模块会缓存搜索结果,为了使对比条件更一致,re.purge()方法清除缓存 re.purge() result=scraper(html) #检查结果 assert(result['area']=='647,500 square kilometres') #结束时间 end=time.time() print '%s: %.2f seconds' %(name,end-start)
结果分析:
由于lxml和正则表达式都是用C语言写的,所以效果比用Python写的BeautifulSoup要好.由于lxml在搜索之前必须输入解析为内部格式,所以会产生额外的开销.而爬取同一网页时这种开销会降低.
方法总结
抓取方法 -性能- 使用难度 -安装难度
正则表达式- 快 -困难- 简单(内置)
Beautiful Soup -慢 -简单- 简单(纯python)
Lxml 快 -简单 -相对困难
如果是下在网页,而不是抽取数据的话,那么使用Beautiful Soup,如果只需抓取少量数据,并且避免额外依赖的话,选择正,通常情况下使用lxml比较合适.