python 爬虫的大致总结

python爬虫的一些总结

爬虫作用

  • 收集数据
  • 尽职调查(即:对公司行为的数据调查)
  • 刷流量和秒杀

正则表达式

正则的基本符号

  1. . 点号: 代替除换行符以外的任何一个字符
  2. * 星号: 前面的子表达式出现 0次无限次
  3. ? 问号: 前面的子表达式出现 0次1次
  4. \ 反斜杠: 转义字符开头
  5. () 小括号: 提取括号里面的内容

python中使用正则表达式

使用正则需要先导入模块

1
import re

此处为部分函数

findall

返回所有满足要求的内容

1
2
3
4
5
6
7
8
9
10
11
re.findall(pattern, string, flags=0)
'''
pattern 正则表达式
string 原来的字符串
flags 特殊功能的标志
@return list 返回匹配到的所有结果,如果没有匹配到结果,就返回空列表
'''
# 例子
content = '我的啥啥啥账号:1231,密码:1516,我的撒撒撒账号:1231,密码:1516,'
#re.findalll(':(.*?),', content)
re.findall('账号:(.*?),密码:(.*?),',content)

返回第一个满足要求的字符串,找到就停止匹配

1
2
3
4
5
6
7
8
re.search(pattern, string, flags=0)
'''
同上
利用.group()获取里面的值
return class 返回正则对象,没匹配到返回 None
group()里面的数值必须小于正则表达式中的 括号
值为 1 时才会将表达式中的内容返回
'''

简单的网页爬取

requests 获取网页源代码

GET 请求

1
2
3
4
5
6
7
import requests
# 获取网页 <Response [200]>
html = requests.get('<string:url>')
# 显示 bytes 型网页源码
html_bytes = html.content
# 将 bytes 网页源代码解码为 字符串型,可设置编码格式(默认UTF-8)。如: .decode('GBK2312')
html_str = html_bytes.decode()

POST 请求

1
2
3
4
5
6
7
8
import requests
data = {
'key1':'value1',
'key2':'value2'
}
# data根据实际情况进行更改
# 有一些网址是提交JSON格式的内容 需要更改一下代码:.post('网址',json=data)
html_formdata = requests.post('网址',data=data).content.decode()

多线程爬虫

目的:提高爬取速度

python 多线程

Python语言在设计时候,有一个全局解释器锁(Global Interpreter Lock, GIL), 导致Python的多线程是伪多线程, 即 本质上还是
一个线程
,但是这个线程每件事只做几毫秒,几毫秒之后就保存现场,换做其他事情,几毫秒之后再做其他的,如此反复。

微观为单线程,在宏观上是多线程。这种机制在 I/O密集型 影响不大,但是在 CPU计算密集型 ,由于只有CPU的一个核,就会对性能产生很大影响

多进程库

multiprocessing 是Python的多进程库,用来处理与多进程相关的操作。但由于进程与进程之间不能直接共享内存和堆栈资源,而且启动新的进程开销也比线程大得多,因此使用多线程来爬取比使用多进程有更多优势。multiprocessing下面有一个dummy模块,可以让Python的线程使用multiprocessing的各种方法。

dummy 下面有一个Pool类,它用来实现线程池。这个线程池有一个map()方法,可以让线程池里面的所有程序都“同时”执行一个函数。

1
2
3
4
5
6
7
8
9
from multiprocessing.dummy import Pool

def calc_power2(num):
return num*num

pool = Pool(3)
origin_num = [x for x in range(10)]
result = pool.map(calc_power2, origin_num)
print(f'计算0-9的平方分别为:{result}')

由于这个例子不涉及I/O操作,所以3个线程代码的运行时间并不小于单线程时间
原因: 线程切换需要时间
导致: 线程池不是越大越好

线程爬虫举例

此处需要了解到,多线程事件驱动的异步模型 是有区别的。动作越多线程的效率越低。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def query(url):
retuests.get(url)

start = time.time()
for i in range(100):
query('https://baidu.com')
end = time.time()
print(f'单线程方位100次百度耗时:{end - start}')

start = time.time()
url_list = []
for i in range(100):
url_list.append('https://baidu.com')
pool = Pool(5)
pool.map(query, url_list)
end = time.time()
print(f'5线程范文100次百度耗时:{end-start}')

高性能HTML内容解析

XPath

XPath(XML Path)是一种查询语句,特能够在XML和HTML的树状结构中寻找节点。
Python使用XPath需要安装第三方库:lxml

附录

  • python函数注意事项

函数外面的容器类作为参数传递到函数后,如果函数修改了这个容器里面的值,那么函数外面的容器也会受到印象
(即:容器改变,普通变量不变)

  • 如何读懂一个类
  1. 这个类有哪些属性(看外貌)
  2. 这个类有哪些方法(能做啥)
  3. 这些方法在哪调用(做啥的)
  4. 这些方法实现的细节(怎么做)
  • .*.*? 的区别

.* 贪婪模式,获取最长的满足条件的字符串
.*? 非贪婪模式,获取最短的能满足条件的字符串