技术选型
scrapy vs requests + beautifulsoup
1,requests和beautifulsoup都是库,scrapy是框架
2,scrapy框架中可以加入requests和beautifulsoup
3,scrapy基于twisted(异步I/O),性能是最大的优势
4,scrapy方便扩展,提供了很多内置的功能
5,scrapy内置的css和xpath selector非常方便,beautifulsoup最大的缺点就是慢(对HTML进行分析)
网页分类
常见类型的服务
1,静态网页(静态博客)
2,动态网页
3,webservice(restapi)
爬虫能做什么
爬虫作用
1,搜索引擎--百度,google,垂直领域搜索引擎
2,推荐引擎--今日头条
3,机器学习的数据样本
4,数据分析(如金融数据分析),舆情分析等。
正则表达式
目录:
1,特殊字符
- ^ $ * ? + {2} {2,} {2,5} |
- [] [^] [a-z] .
- \s \S \w \W
- [\u4E00-\u9FA5] () \d
2,正则表达式的简单应用及python示例
栗子1:
import re
line = "bobby123"
regex_str = "^b.*"
if re.match(regex_str,line):
print("yes")
栗子二:
import re
line = "boooooooobby123"
regex_str = ".*?(b.*?b).*"
mathch_obj = re.match(regex_str,line)
if mathch_obj:
print(mathch_obj.group(1))
当没有加 ? 的时候是贪婪匹配(从最后开始匹配),加了之后是非贪婪模式(从前面开始匹配)。
注意: [ ] 里面的特殊字符不再有特殊含义,[ * ]就是匹配 *
栗子三:
import re
line = "你 好"
regex_str = "(你\s好)"
mathch_obj = re.match(regex_str,line)
if mathch_obj:
print(mathch_obj.group(1))
栗子四:
import re
line = "你好s"
regex_str = "([\u4E00-\u9FA5]+)"
mathch_obj = re.match(regex_str,line)
if mathch_obj:
print(mathch_obj.group(1))
使用[\u4E00-\u9FA5]可以匹配连续的中文
我们看下一个字符串中除了中文还有其它字符的时候,我们想提取大学前面和大学
import re
line = "study in 南京大学"
regex_str = ".*?([\u4E00-\u9FA5]+大学)"
mathch_obj = re.match(regex_str,line)
if mathch_obj:
print(mathch_obj.group(1))
深度优先和广度优先
目录:
1,网站的树结构
2,深度优先算法和实现
3,广度优先算法和实现
网站url的结构图:伯乐在线
网站设计是分层的,多级域名的。
网站url链接的结构图
为了防止循环爬取,对已经爬取过的链接新建一个list存放。在爬取之前,我们进行一次判断,如果没有爬取过,才爬取。
深度优先图:
深度优先:每次爬取到无链接可爬取为止,然后向上层返回查找。
广度优先:每次爬取当前页面可访问的所有兄弟节点。(分层)
1,深度优先输出A,B,D,E,I,C,F,G,H(递归实现)
2,广度优先输出A,B,C,D,E,F,G,H,I(队列实现)
深度优先过程:
In [1]: 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)
...:
注意:递归太深会导致栈溢出
广度优先过程:
In [4]: def level_queue(root):
...: """利用队列实现树的广度优先遍历"""
...: if root is 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)
...:
爬虫去重策略
1,将访问过的url保存到数据库中
(每次拿到一个新的url都会去数据库查询是否被爬取过,效率低)
2,将访问过的url保存到内存set中,只需要O(1)的代价就可以查询url
假设有一亿个url,占用内存:
1000000002byte50个字符/1024/1024/1024 = 9G
3,url经过md5等方法哈希后保存到set
经过编码之后,可以对数据压缩
4,用bitmap方法,将访问过的url通过hash函数映射到某一位
将url映射到byte的位上,但是具有高冲突
5,bloomfilter方法对bitmap进行改进,多重hash函数降低冲突
字符串编码
utf8编码在保存和网络传输的时候,使用的空间较小。
而unicode编码在编程的时候,因为字节统一,便于编程。
因此文件文件保存的时候,我们保存为utf-8的格式,读取到内存的时候,我们转化为Unicode编码。当由内存保存至文件的时候,我们再将编码改为utf-8的编码格式。
获取系统默认编码
In [1]: import sys
In [2]: sys.getdefaultencoding
Out[2]: <function sys.getdefaultencoding>
In [3]: sys.getdefaultencoding()
Out[3]: 'utf-8'
想要encode之前要保证字符串是Unicode格式。