热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

2018.2最新Scrapy+elasticSearch+Django打造搜索引擎直至部署上线(三)

最终项目上线演示地址:http:search.mtianyan.cn第三节:本节我们先得了解点你做爬虫做搜索引擎的居家必备知识基础。Github地址:https:gi

最终项目上线演示地址: http://search.mtianyan.cn

  • 第三节:本节我们先得了解点你做爬虫做搜索引擎的居家必备知识基础。

Github地址: https://github.com/mtianyan/ArticleSpider (欢迎先点个star后上车)

爬虫基础知识
  1. 正则表达式
  2. 深度优先和广度优先遍历算法
  3. url去重的常见策略

技术选型

scrapy vs requests+beautifulsoup

  • requests和beautifulsoup都只是库,scrapy是框架。
  • scrapy 可以加入requests和beautifulsoup
  • scrapy基于twisted(异步IO框架),性能好
  • 方便扩展,有很多内置功能
  • 内置的cssxpath selector(lxml:c实现的框架)很方便,速度快

beautifulsoup最大的缺点就是慢。

pip install scrapy

可能遇到的报错信息: Failed building wheel for Twisted

http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted 本地安装

网页分类

  1. 静态网页
  2. 动态页面
  3. webservice(restful api): 前台通过ajax与后台进行交互

爬虫能做什么?

  1. 搜索引擎:百度 垂直领域搜索引擎(只爬某领域)
  2. 推荐引擎:今日头条
  3. 机器学习的数据样本
  4. 数据分析(金融数据分析) 舆情分析

正则表达式

为什么必须会正则表达式?

应用场景: 1天前中提取出1

特殊字符:

可以判断是否匹配模式,字符串中提取指定字符

  • ^:代表以该字符为开头。如^b就是b为开头。
  • .: 代表任意一个字符。如^b.就是b开头后面一个字母任意
  • *: 代表前一个字符可以出现任意次(0个也可以)。如^b.*就是b开头后面可有任意数个任意字母
  • $: 代表前一个字符为结尾符合。 如:.*3$就是以3为结尾的任意字符串
  • ?: 在限定次数词后加一个"?",则表示匹配尽可能少的字符: 非贪婪匹配。
    • 一般情况从右往左匹配正则,非贪婪遇到符合最小条件就返回。
    • ?可以实现从左往右,非贪婪指遇到第一个就结束。
      .*?(b.*?b).*就是首先开始的b和找到的第一个b之间的字符串,不向后贪婪。

Example Code

# encoding: utf-8
__author__ = 'mtianyan'
__date__ = '2018/1/17 0017 16:20'import reline1 = "mtianyan123"
line2 = "moooommtianyan123"# 定义正则表达式的字符串模式
# ^m代表以m开头;.代表任意字符;* 代表前面字符可以重复任意遍
# 3$代表以3为结尾
regex_str1 = "^m.*3$"# 两个参数: 定义的字符串,以及我们要检验的字符串
if re.match(regex_str1, line1):print("yes")# 默认为贪婪模式: 反向由字符串模式从右向左匹配
# m前面无所谓啥,m和后一个m中间无所谓啥。后面也无所谓有啥。目标:moooom
# 括号括起来我们需要的字符串.也就是只提取这一部分。
regex_str2 = ".*(m.*m).*"
match_obj = re.match(regex_str2, line2)
if match_obj:# 只取第一个括号东西。print (match_obj.group(1))
# mm# 使用?使他从左边开始但是右边还是贪婪模式匹配。从右匹配到右起第一个
regex_str3 = ".*?(m.*m).*"
match_obj = re.match(regex_str3, line2)
if match_obj:# 只取第一个括号东西。print (match_obj.group(1))
# moooomm# 使用?使他从左边开始但是右边还是贪婪模式匹配。
# 在第二个m前也加问号。让它从左起开始。找这样的条件的b,不要继续向后贪婪
regex_str4 = ".*?(m.*?m).*"
match_obj = re.match(regex_str4, line2)
if match_obj:# 只取第一个括号东西。print (match_obj.group(1))
# moooom

  • 两个问号都不加: 默认从右开始找匹配模式的字符,找到即返回。
  • 加前面一个问号: 从左开始,但是会一直贪婪到最长的符合字符。因为后面m还是从右开始的。

  • 后面加一个问号: 第二个字符从左开始找。

  • 两个问号都加:从左开始找字符m 和 m

  • +: 代表前面的字符至少出现一次: 如b.+b指两个b之间至少一个字符

+*{2}都属于限定词限定前面出现多少次

  • {2} {2,5} {2, }:
    • 代表前面的字符出现2次。
    • 代表前面的字符出现2到5次.
    • 代表前面字符出现2次及两次以上
  • |:代表的意思 b|c,在模式字符串从左到右, 看先匹配到那个。先找b
  • (): 代表子字符串。如((a|b)123)代表group(1)为外层括号里的a123|b123;group(2)为内层括号值 a b
  • []: 代表[]内的字符满足任意一个都可以。
    • [abcdefg]123代表以abcdefg中一个字母开头的,后面是123的都可以。
  • [0-9] [a-z]
    • 代表可以为0-9范围内任意一个字符
    • 代表a-z范围任意一个字符
  • [^1] ^为取反,只要不等于1就可以

注: 进入[]的字符都不再具有特殊含义[.*]就指匹配到.或者*

  • \s \S
    • \s代表匹配到一个空格。
    • \S代表匹配到一个非空格
  • \w \W
    • 匹配任意字符 等价: [a-zA-Z0-9_]
    • 非单词字符
  • [\u4E00-\u9FA5]: 匹配中文汉字

"study in 浙江大学" 匹配regex_str = .*?[\u4E00-\u9FA5]+大学

如果不加问号。则从右开始,只会匹配到江大学

  • \d: 匹配数字

例子: "xxx出生于2001年" 匹配.*?(\d+)年

不加?会只匹配到1.因为它从右往左找第一个符合条件的。

  • 加上问号,从左往右,找到符合条件的。

import reline = "XXX出生于2001年"
# line = "XXX出生于2001/6/1"
# line = "XXX出生于2001-6-1"
# line = "XXX出生于2001-06-01"
# line = "XXX出生于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))

([月/-]\d{1,2}日|[月/-]\d{1,2}|[月/-]$|$)满足或的关系

深度优先和广度优先

  1. 网站的树结构
  2. 深度优先算法和实现
  3. 广度优先算法和实现

网站url树结构:

分层设计
子域名:

  1. jobbole.com
    1.1 blog.bogbole.com
    1.2 python.bogbole.com
    1.1.1 python.bogbole.com/123
mark

上图为网站的实际url结构图,可以看到其中的环路链接:

从首页到某个具体页面节点。
但是下面的链接节点又会有链接指向首页,这样会让爬虫自己在里面转圈圈。

去重, 建立已爬取url列表

  1. 深度优先
  2. 广度优先

跳过已爬取的链接, 对于二叉树的遍历问题

mark

深度优先(递归实现):

顺着一条路,走到最深处。然后回头。

输出: A->B->D->E->I->C->F->G-H (scrapy默认使用)

广度优先(队列实现):

分层遍历:遍历完儿子辈。然后遍历孙子辈

输出: A->B->C->D->E->F->G->H->I

Python实现深度优先过程code:

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)

递归太深没有跳出,会造成内存溢出。

Python实现广度优先过程code:

def level_queue(root):#利用队列实现树的广度优先遍历if root is None:returnmy_queue = []node = rootmy_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)

爬虫去重策略

  1. 将访问过的url保存到数据库中,获取url时查询一下是否爬过了。
  2. 将url保存到set中。只需要O(1)的代价就可以查询到url
  3. url经过md5等方法哈希后保存到set中,将url压缩到固定长度而且不重复
  4. bitmap方法,将访问过的url通过hash函数映射到某一位.
  5. bloomfilter方法对bitmap进行改进,多重hash函数降低冲突可能性。

方法2保守估计:100000000*2byte*50个字符/1024/1024/1024 = 9G,占用内存过大。

scrapy去重使用的是第三种方法:

后面分布式scrapy-redis会讲解bloomfilter方法。hash函数会引起冲突,冲突解决。

Python字符串编码问题解决:

  1. 计算机只能处理数字,文本转换为数字才能处理,计算机中8个bit作为一个字节,
    所以一个字节能表示的最大数字就是255。
  2. 计算机是美国人发明的,所以一个字节就可以标识所有单个字符
    ,所以ASCII(一个字节)编码就成为美国人的标准编码
  3. 但是ASCII处理中文明显不够,中文不止255个汉字,所以中国制定了GB2312编码
    ,用两个字节表示一个汉字。GB2312将ASCII也包含进去了。同理,日文,韩文,越来越多的国家为了解决这个问题就都发展了一套编码,标准越来越多,如果出现多种语言混合显示就一定会出现乱码
  4. 于是unicode出现了,通过16个bit, 32个bit.它将所有语言包含进去了。
  5. 看一下ASCII和unicode编码:
    • 字母A用ASCII编码十进制是65,二进制 0100 0001
    • 汉字"中" 已近超出ASCII编码的范围,用unicode编码是20013二进制是01001110 00101101
    • A用unicode编码只需要前面补0二进制是 00000000 0100 0001
  6. 乱码问题解决了,但是如果内容全是英文,unicode编码比ASCII编码需要多一倍的存储空间,传输也会变慢。
  7. 所以此时出现了可变长的编码"utf-8" ,把英文:1字节,汉字3字节,特别生僻的变成4-6字节,如果传输大量的英文,utf8作用就很明显。

Unicode编码虽然占用空间但是因为占用空间大小等额,在内存中处理会简单一些。

读取文件,进行操作时:转换为unicode编码进行处理
保存文件时,转换为utf-8编码。以便于传输

mark

读文件进行decode(解码)操作转码为Unicode,但是decode必须指明原始编码方式。
Unicode编码 encode(编码) 操作转码为其他我们指定编码格式。

读文件的库都会自动将文件转换为Unicode编码,但需要我们指明编码。

Python3中将所有字符转换为Unicode。

python2 默认编码格式为ASCII,Python3 默认编码为 utf-8

#python3
import sys
sys.getdefaultencoding()
s.encoding('utf-8')

#python2
import sys
sys.getdefaultencoding()
s = "我和你"
su = u"我和你"
~~s.encode("utf-8")#会报错~~
s.decode("gb2312").encode("utf-8")
su.encode("utf-8")

mark

内存中是通过Unicode进行编码的, s 是一个非Unicode的编码。windows下是gb2312编码。Linux下是utf-8的编码。

encode方法之前,必须确保前面的变量是Unicode。

mark

说明windows中s确实是gb2312保存的,而且decode方法并不会直接改变字符串本身。而是返回一个编码过后的字符串。

mark

说明Linux中s是以utf-8保存的。encode编码之前必须走中间路径: 转换为Unicode

mark
mark

可以看到windows和Linux的默认编码格式都是ascii、

Python2文件头添加utf-8编码说明。可以使得读文件的解释器指定decode的参数。
Python3已经不用加了,因为它把默认的s取消掉了。直接将字符串全部当unicode处理。
可以直接编码。

mark

可以看到windows,Linux中Python3的默认编码为utf-8.




推荐阅读
  • 阿里Treebased Deep Match(TDM) 学习笔记及技术发展回顾
    本文介绍了阿里Treebased Deep Match(TDM)的学习笔记,同时回顾了工业界技术发展的几代演进。从基于统计的启发式规则方法到基于内积模型的向量检索方法,再到引入复杂深度学习模型的下一代匹配技术。文章详细解释了基于统计的启发式规则方法和基于内积模型的向量检索方法的原理和应用,并介绍了TDM的背景和优势。最后,文章提到了向量距离和基于向量聚类的索引结构对于加速匹配效率的作用。本文对于理解TDM的学习过程和了解匹配技术的发展具有重要意义。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 深度学习中的Vision Transformer (ViT)详解
    本文详细介绍了深度学习中的Vision Transformer (ViT)方法。首先介绍了相关工作和ViT的基本原理,包括图像块嵌入、可学习的嵌入、位置嵌入和Transformer编码器等。接着讨论了ViT的张量维度变化、归纳偏置与混合架构、微调及更高分辨率等方面。最后给出了实验结果和相关代码的链接。本文的研究表明,对于CV任务,直接应用纯Transformer架构于图像块序列是可行的,无需依赖于卷积网络。 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • 安装mysqlclient失败解决办法
    本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了Linux系统中正则表达式的基础知识,包括正则表达式的简介、字符分类、普通字符和元字符的区别,以及在学习过程中需要注意的事项。同时提醒读者要注意正则表达式与通配符的区别,并给出了使用正则表达式时的一些建议。本文适合初学者了解Linux系统中的正则表达式,并提供了学习的参考资料。 ... [详细]
  • 本文详细介绍了MySQL表分区的创建、增加和删除方法,包括查看分区数据量和全库数据量的方法。欢迎大家阅读并给予点评。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
author-avatar
豆伊一
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有