爬虫基础知识

                                           爬虫基础知识

 


一、技术选型 爬虫能做什么

    1、scrapy VS requests+beautifulsoup

        (1) requests和beautifulsoup都是库,scrapy是框架;

        (2) scrapy框架可以加入requests和beautifulsoup;

        (3) scrapy基于twisted,性能是最大的优势;

        (4) scrapy方便扩展,提供了很多内置功能;

        (5) scrapy内置的css和xpath selector非常方便,beautifulsoup最大的缺点就是慢。

    2、常见类型的服务

        (1) 静态网页

        (2) 动态网页

        (3) webservice(restapi)

    3、爬虫作用

        (1) 搜索引擎---百度、google、垂直领域搜索引擎

        (2) 推荐引擎---今日头条

        (3) 机器学习数据样本

        (4) 数据分析(如金融数据分析)、舆情分析等

二、正则表达式

    1、特殊字符

        (1) ^ $ * ? + {2} {2,} {2,5} |       

        示例一:(^: 表示以什么开头)

import re

line = 'caoxuejin520'
regex_str = "^c.*"
if re.match(regex_str, line):
    print("yes")
else:
    print("no")

        输出:yes   

        示例二:($: 表示以什么结尾)

import re

line = 'caoxuejin520'
regex_str = ".*0$"
if re.match(regex_str, line):
    print("yes")
else:
    print("no")

        输出:yes

        示例三:(*: 表示前面的字符可以出现任意多次)

import re

line = 'caoxuejin520'
regex_str = "^c.*0$"
if re.match(regex_str, line):
    print("yes")
else:
    print("no")

        输出:yes        

        示例四:(?: 表示非贪婪匹配模式--从左往右匹配;贪婪匹配模式--从右往左匹配)        

import re

line = 'caocaoxxuejin520'
regex_str = ".*?(c.*?x).*"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:caocaox

         示例五:(+: 表示加号前面的字符至少出现一次)        

import re

line = 'caocaoxxuejin520'
regex_str = ".*(c.+?x).*"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:caox  

        示例六:({1}: 表示前面的字符出现1次)   

line = 'caocaoxxuejin520'
regex_str = ".*(c.{2}x).*"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:caox

        示例七:({2,}: 表示前面的字符出现2次或2次以上)   

import re

line = 'caocaoxxuejin520'
regex_str = ".*(c.{2,}x).*"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:caoxx

        示例八:({2,5}: 表示前面的字符出现最少2次最多5次)   

import re

line = 'caocaoxxuejin520'
regex_str = ".*(c.{2,5}x).*"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:caoxx

        示例八:(|: 表示或) 

import re

line = 'caoxuejin520'
regex_str = "(caoxuejin|caoxuejin520)"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:caoxuejin  

import re

line = 'caoxuejin520'
regex_str = "(caoxuejin520|caoxuejin)"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:caoxuejin520

import re

line = 'caoxuejin520'
regex_str = "(caoxxuejin|caoxuejin)520"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:caoxuejin

import re

line = 'caoxuejin520'
regex_str = "((caoxxuejin|caoxuejin)520)"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:caoxuejin520

        (2) [] [^] [a-z] .

        示例:([34578]: 表示应该是集合中的任何一个数值;[0-9]: 表示在0-9区间内;[^1]: 表示不等于1)

import re

line = '15736170030'
regex_str = "(1[34578][0-9]{9})"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出: 15736170030

import re

line = '15sssssssss'
regex_str = "(1[34578][^1]{9})"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:15sssssssss

        (3) \s \S \w \W

        示例一:(\s: 表示空格)

line = '你 好'
regex_str = "(你\s好)"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:你 好

        示例二:(\S: 表示匹配一个任意字符)

import re

line = '你很好'
regex_str = "(你\S好)"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:你很好

import re

line = '你非常好'
regex_str = "(你\S+好)"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:你非常好

        示例三:(\w: 表示[A-Za-z0-9_]---数字、字母、下划线)

import re

line = '你_好'
regex_str = "(你\w好)"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:你_好

        示例四:(\W: 与\w相反,表示非[A-Za-z0-9_]---非数字、字母、下划线)        

import re

line = '你-好'
regex_str = "(你\W好)"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:你-好

        (4) [\u4E00-\u9FA5] () \d   

        示例一:([\u4E00-\u9FA5]: unoicode编码,匹配汉字) 

import re

line = 'study in 北京大学'
regex_str = ".*?([\u4E00-\u9FA5]+大学)"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:北京大学

        示例二:(\d: 表示数字) 

import re

line = 'xxx出生于2001年'
regex_str = ".*?(\d+)年"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

        输出:2001

        附加:.: 表示任意字符;(): ()内的内容表示的是一个子表达式

    2、正则表达式的简单应用及python示例

        实例:检索出生年月日

#line = 'xxx出生于2001年6月1日'    # 2001年6月1日
#line = 'xxx出生于2001/6/1'       # 2001/6/1
#line = 'xxx出生于2001-6-1'       # 2001-6-1
#line = 'xxx出生于2001-06-01'     # 2001-06-01
line = 'xxx出生于2001-06'         # 2001-06
regex_str = ".*出生于(\d{4}[年/-]\d{1,2}([月/-]\d{1,2}日|[月/-]\d{1,2}|[月/-]$|$))"
match_obj = re.match(regex_str, line)
if match_obj:
    print(match_obj.group(1))

 

三、深度优先和广度优先

    1、网站的树结构

        (1) 网站url的结构图

            

        (2) 网站url链接的结构图

            

    2、深度优先算法实现

        输出:A、B、D、E、I、C、F、G、H(递归实现)

        过程:

def depth_tree(tree_node):
    if tree_node is not None:
        print(tree_node._data)
        if tree_node._left is not None:
            return depth_tree(tree_node._left)
        if tree_node._right is not None:
            return depth_tree(tree_node._right)

    3、广度优先算法和实现

        输出:A、B、C、D、E、F、G、H、I(队列实现)

        过程:

def level_queue(root):
    """利用队列实现树的广度优先遍历"""
    if root is not None:
        return
    my_queue = []
    node = root
    my_queue.append(node)
    while my_queue:
        node = my_queue.pop(0)
        print(node.elem)
        if node.lchild is not None:
            my_queue.append(node.lchild)
        if node.rchild is not None:
            my_queue.append(node.rchild)

四、url去重方法

    1、将访问过的URL保存到数据库中

    2、将访问过的URL保存到set中,只需要o(1)的代价就可以查询URL

       1000000000*2byte*50个字符/1024/1024/1024 = 9G

    3、URL经过md5等方法哈希后保存到set中

    4、用bitmap方法,将访问过的URL通过hash函数映射到某一位

        

    5、bloomfilter方法对bitmap进行改进,多重hash函数降低冲突

五、彻底搞清楚unicode和utf8编码

    1、字符串编码

        (1) 计算机只能处理数字,文本转换为数字才能处理。计算机中8个bit作为一个字节,所以一个字节能表示最大的数字就是255;

        (2) 计算机是美国人发明的,所以一个字节可以表示所有字符了,所以ASSCII(一个字节)编码就成为美国人的标准编码;

        (3) 但是ASCII处理中文明细是不够的,中文不止255个汉字,所以中国制定了GB2312编码,用两个字节表示一个汉字。GB2312还把ASCII包含进去了,同理,日文,韩文等等上百个国家为了解决这个问题就都发展了一套字节编码,标准就越来越多,如果出现多种语言混合显示就一定会出现乱码;

        (4) 于是unicode出现了,将所有语言统一到一套编码里;

        (5) 看一下ASCII和unicode编码:

            a. 字母A用ASCII编码十进制是65,二进制是0100 0001

            b. 汉字“中”已经超出了ASCII编码的范围,用unicode编码是20013,二进制是01001110 00101101

            c. A用unicode编码只需要前面补0,二进制是00000000 0100 0001

        (6) 乱码问题解决了,但是如果内容全是英文,unicode编码比ASCII需要多一倍的存储空间,同时如果传输需要多一倍的传输;

        (7) 所以出现了可变长的编码"utf-8",把英文变为一个字节,汉字3个字节。特别生僻的变成4-6字节,如果传输大量的英文,utf8作用就很明显了。

        

    2、实例

        (1) python2 

Python 2.7.14 (default, Sep 23 2017, 22:06:14) 
[GCC 7.2.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> s = 'abc'
>>> su = u'abc'
>>> s.encode("utf-8")
'abc'
>>> su.encode("utf-8")
'abc'
>>> s = "我用python"
>>> su = u"我用python"
>>> s.decode("utf-8").encode("utf-8")
'\xe6\x88\x91\xe7\x94\xa8python'
>>> su.encode("utf-8")
'\xe6\x88\x91\xe7\x94\xa8python'
>>> import sys
>>> sys.getdefaultencoding()
'ascii'

        (2) python3

Python 3.5.6 (default, Sep 10 2018, 10:36:11) 
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> s="我用python"
>>> s.encode("utf-8")
b'\xe6\x88\x91\xe7\x94\xa8python'
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'
>>> 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值