CSS 选择器:BeautifulSoup4
Beautiful Soup 是基于HTML DOM的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多,所以性能要低于lxml。
用来解析 HTML 比较简单,API非常人性化,支持CSS选择器、Python标准库中的HTML解析器,也支持 lxml 的 XML解析器。
解析器 | 使用方法 |
---|---|
Python标准库 | BeautifulSoup(markup,‘html.parser’) |
lxml HTML解析器 | BeautifulSoup(markup,‘lxml’) |
lxml XML解析器 | BeautifulSoup(markup,‘xml’) |
html5lib | BeautifulSoup(markup,‘html5lib’) |
代码如下:
#导入bs4
from bs4 import BeautifulSoup
<html>
.......
#创建 Beautiful Soup 对象,
初始化 soup=BeautifulSoup(html文本,'lxml')
findall()方法:
参数 | 说明 |
---|---|
name参数 | 可以根据节点名查询 |
attrs参数 | 可以根据节点属性查询 |
text参数 | 用来匹配节点文本 |
css选择器:
表达式 | 说明 |
---|---|
#container | 选择id为container的节点 |
container | 选取所有class包含container的节点 |
li a | 选取所有li下的所有a节点 |
div#container > ul | 选取id为container的div的ul子元素 |
li:nth-child(3) | 选取第三个li元素 |
通过标签名查找:
- soup.select(‘title’)
- soup.select(‘b’)
通过类名查找
- soup.select(’.sister’)
通过id查找
- print soup.select(’#link1’)
获取属性(例如获取标签属性) a.attrs[‘id’] 或者 a[‘id’] 获取文本 a.get_text()或者a.string
PyQuery
初始化
有 4 种方法可以进行初始化: 可以通过传入 字符串、lxml、文件 或者 url 来使用PyQuery。
#传入字符串
d = pq("")
#传入lxml
d = pq(etree.fromstring(""))
#传入url
d = pq(url=‘http://google.com/’)
#传入文件
d = pq(filename=path_to_html_file)
现在,d 就像 jQuery 中的 $ 一样了。
方法
> `.find():查找嵌套元素
.filter(selector):根据 class、id 筛选指定元素
.eq(index):根据索引号获取指定元素(index 从 0 开始)
pq_html(selector):通过css选择器来获取目标内容
.text() 获取标签的文本
.attr('属性值'):获取标签属性
线程
#\ 线程: 多任务方式之一,可以提高执行任务的效率
1.线程是cpu执行的基本单元,
2.线程的执行是无序的
3.同一进程下的线程之间资源是共享的(互斥锁)
4.线程多用来处理I/O密集型任务
使用方法
使用模块 import threading
def run1(num):
# global data
global sum
lock.acquire() #枷锁
for i in range(num):
# print(kwargs)
# print('我是线程1')
# print(i,threading.currentThread().name)
# data.append(i)
sum += 1
lock.release() #解锁
if __name__ == '__main__':
lock = threading.Lock()
td2 = threading.Thread(target=run2,name='线程1',args=(10000000,))
td2.start() # 启动线程,即让线程开始执行
td2.join() #在这里表示并发阻塞
print('执行完毕',sum)
参数如下:
target=None : 线程执行的任务函数
name=None: 线程的名称
args=(), 元祖类型,是任务函数需要传递的参数
kwargs=None, dict类型,是任务函数需要传递的参数
*,join()方法 线程阻塞,让子线程中的任务执行完毕,再回到主线程中继续执行
daemon=None: 默认为False,主线程结束时会对子线程轮循,如果daemon=True,则主线程结束子线程
也会随之结束
保护资源,threading.Lock() 添加了线程锁之后,保证同一时刻只能有一个线程在使用或修改资源
注意
线程执行是无顺序的,
线程资源是共享的,保护资源,threading.Lock() 添加了线程锁之后,保证同一时刻只能有一个线程在使用或修改资源,注意避免死锁情况的发生!!!
线程池
用法代码如下:
导入线程池
from concurrent.futures import ThreadPoolExecutor
实例化ThreadPoolExecutor
pool = ThreadPoolExecutor(10) #10表示有多少个线程
#提交任务到线程池
往线程池中提交任务
"""
fn(要执行的任务), *args(要传递的参数), **kwargs(要传递的参数)
"""
result = pool.submit(crawlPageDate,url,name='1808')
给线程添加后调方法(add_done_callback添加的是方法名)
result.add_done_callback(done)