返回列表 发新帖

Python开发简单爬虫

[复制链接]
     

该用户从未签到

118

主题

120

帖子

362

积分

中级会员

Rank: 3Rank: 3

积分
362
发表于 2018-2-12 17:49:21  | 显示全部楼层 | 阅读模式
什么是爬虫?
通俗的讲,爬虫就是通过一个URL开始,自动获取数据的“网络机器人”。

简单的爬虫架构



URL管理器记录爬取过的URL和未爬取的URL
从URL管理器中获取一个未爬取的URL下载网页内容
解析爬取到的内容,将价值数据存储起来,将爬到的新URL传递给URL管理器存储为未爬取的URL,并从2开始循环执行
URL管理器

存储未爬取的URL和爬取过的URL

作用

防止重复抓取。爬取过后的URL存在已爬取URL集合中,不再去访问
防止循环抓取。如果A网页包含B网页的链接,B网页包含A网页的链接,可能导致无限循环。每次添加URL时,判断未爬取URL集合、已爬取URL集合可以避免
需要实现的功能

可以添加新的URL到未爬取集合中,该功能需要判断新的URL是否在URL管理器容器中
判断是否还有未爬取的URL
获取一个待爬取的URL,该功能需要从未爬取的URL集合中删除该URL,并添加到已爬取的URL集合中
实现方式

使用Python,用两个Set分别表示
使用Mysql等数据库存储
使用Redis等,也可以使用两个Set分别表示
网页下载器

将互联网上URL对应的网页下载到本地的工具,本文介绍Python自带库“urllib2”

"urllib2"使用方法

最简单的使用方法



添加data、http header



添加特殊情景的处理器(HTTPCookieProcessor、ProxyHandler、HTTPSHandler、HTTPRedirectHandler)

以添加HTTPCookieProcessor为例:



网页解析器

网页解析器是从网页中提取有价值数据的工具。



常见的几种网页解析器

正则表达式:可以模糊匹配网页字符串里中的内容,在比较复杂的数据中非常麻烦
html.parser:Python自带的解析器
lxml:第三方插件,可以解析html和xml
Beautiful :第三方插件,它既可以使用html.parser作为解析器,也可以使用lxml作为解析器,功能比较强大,推荐使用
其中,正则表达式是基于文本的模糊匹配;其他3种方式将网页文档解析为 DOM 树解析。



Beautiful Soup介绍

官网: https://www.crummy.com/software/BeautifulSoup/



对Beautiful Soup进行操作的一般步骤

先根据HTML网页字符串创建Beautiful Soup对象。
获取节点,可以通过节点名称、属性值、文字搜索节点。 find_all 会搜索所有满足要求的节点, find 搜索出满足要求的第一个节点。
访问节点,获取节点的名称、属性、文字的值。


函数介绍

创建Beautiful Soup对象



搜索节点(find_all,find)



访问节点信息



爬虫实例

分析

确定目标

也就是说:我们需要扒取哪个网站和哪些数据。

本实例我们确定要抓取百度百科“python”词条这个页面和它相关的页面,数据包括页面内的关键词、简介。

分析目标

本实例抓取的URL是页面中的其他词条的超链接,格式类似于 <a href="/item/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E8%AF%AD%E8%A8%80">计算机程序设计语言</a>

本实例都是字符串格式的数据

百度百科网页使用 utf-8 编码,所以在编写代码中注意转码

确定编码,确保程序中的编码格式
抓取的数据格式,用于存储数据
URL格式,用来限定抓取页面的范围
编写代码
执行爬虫

编码

主模块

# -*- coding:utf-8 -*-import url_managerimport html_downloaderimport html_parserimport html_outputerclass SpiderMain(object):

    def __init__(self):
        self.urls = url_manager.UrlManager() # 初始化URL管理器
        self.downloader = html_downloader.HtmlDownloader() # 初始化网页下载器
        self.parser = html_parser.HtmlParser() # 初始化网页解析器
        self.outputer = html_outputer.HtmlOutputer() # 初始化数据输出器

    def craw(self,root_url):
        count = 1  # 记录成功条数
        self.urls.add_new_url(root_url) # 添加url到url管理器
        while self.urls.has_new_url():            try:
                new_url = self.urls.get_new_url() # 获取未爬过的url
                print 'craw %d : %s' %(count, new_url)
                html_cont = self.downloader.download(new_url) # 根据url下载网页
                new_urls, new_data = self.parser.parse(new_url, html_cont) # 解析网页内容
                self.urls.add_new_urls(new_urls) # 将爬到的新网址添加到url管理器
                self.outputer.collect_data(new_data) # 将内容添加到数据输出器

                if count == 1000:                    break

                count = count + 1
            except:                print 'craw failed'


        self.outputer.output_html() # 输出内容# main函数if __name__ == '__main__':
    root_url = 'https://baike.baidu.com/item/Python' # 最开始的url
    obj_spider = SpiderMain()
    obj_spider.craw(root_url)
URL管理器

# -*- coding:utf-8 -*-# URL管理器class UrlManager(object):

    def __init__(self):
        self.new_urls = set() # 存放未读取url
        self.old_urls = set() # 存放已读取url

    # 添加一个url到未读url列表
    def add_new_url(self, url):
        if url is None:            return
        if url not in self.new_urls and url not in self.old_urls:
            self.new_urls.add(url)    # 添加多个url到未读url列表
    def add_new_urls(self, urls):
        if urls is None or len(urls) == 0:            return
        for url in urls:
            self.add_new_url(url)    # 返回是否有未读url
    def has_new_url(self):
        return len(self.new_urls) != 0

    # 随机获取一个未读url
    def get_new_url(self):
        new_url = self.new_urls.pop() # 获取未读url并删除
        self.old_urls.add(new_url) # 添加这个url到已读url列表中
        return new_url
网页下载器

# -*- coding:utf-8 -*-import urllib2# 网页下载器class HtmlDownloader(object):

    # 获取服务器响应内容
    def download(self,url):
        if url is None:            return None

        response = urllib2.urlopen(url)        if response.getcode() != 200: # 获取成功标识
            return None

        return response.read()
网页解析器

# -*- coding:utf-8 -*-from bs4 import BeautifulSoupimport re# 网页解析器class HtmlParser(object):

    # 获取其中的url
    def __get_new_urls(self,page_url, soup):
        new_urls = set()
        links = soup.find_all('a', href=re.compile(r'/item/[a-zA-Z0-9%]+')) # 匹配url,可能会发生变化
        for link in links:
            new_url = link['href'].encode('utf-8') # 获取url
            new_full_url = 'https://baike.baidu.com'+new_url # 拼接url
            new_urls.add(new_full_url)        return new_urls    # 获取其中的内容(关键词,简介)
    def __get_new_data(self,page_url,soup):
        res_data = {}

        res_data['url'] = page_url        # 获取关键词
        title_node = soup.find('dd', class_ = 'lemmaWgt-lemmaTitle-title').find('h1')
        res_data['title'] = title_node.get_text()        # 获取简介
        summary_node = soup.find('div', class_ = 'lemma-summary')
        res_data['summary'] = summary_node.get_text()        return res_data    # 解析htnl字符串
    def parse(self,page_url,html_cont):
        if page_url is None or html_cont is None:            return

        soup = BeautifulSoup(html_cont, 'html.parser', from_encoding='utf-8')
        new_urls = self.__get_new_urls(page_url, soup)
        new_data = self.__get_new_data(page_url, soup)        return new_urls, new_data
数据输出器

# -*- coding:utf-8 -*-# 数据输出器class HtmlOutputer(object):

    def __init__(self):
        self.datas = list()    # 添加数据到列表中
    def collect_data(self, data):
        if data is None:            return
        self.datas.append(data)    # 输出到html文件中
    def output_html(self):
        fout = open(r'output.html','w')

        fout.write('<html>')
        fout.write('<body>')
        fout.write('<table>')        for data in self.datas:
            fout.write('<tr>')
            fout.write('<td>%s</td>' % data['url'])
            fout.write('<td>%s</td>' % data['title'].encode('utf-8'))
            fout.write('<td>%s</td>' % data['summary'].encode('utf-8'))
            fout.write('</tr>')


        fout.write('</table>')
        fout.write('</body>')
        fout.write('</html>')

        fout.close()
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
关于我们
友情链接
联系我们
帮助中心
网友中心
购买须知
支付方式
服务支持
资源下载
售后服务
定制流程
关注我们
官方微博
官方空间
官方微信
快速回复 返回顶部 返回列表