数据格式
- xml:
- 可扩展标记语言
- 被设计为传输和存储数据,其焦点是数据的内容
- html:
- 超文本标记语言
- 显示数据以及如何更好的显示数据
xpath 重点
-
使用xpath helper 或者是chrome中的copy xpath都是从element中提取数据,但是爬虫获取的是url对应的响应,往往和elements不一样
-
获取文本
a/text()
获取a下的文本a//text()
获取a下面所有标签的文本//a[text()='下一页 >']
选择文本为下一页的三个字
-
获取属性
@
符号a/@href
获取a的href属性//ul[@id="aaa"]
获取页面上所有的ul并且id为aaa的
-
同级
.
-
上一级
..
-
第一个斜杠代表的是根目录
/
-
//
- 在xpath开始的时候,表示从点前html中任意位置开始选择
//ul
:页面上所有的ulli//a
表示的是li下的任何一个标签- 选某一个,正着选:[1],[2],[3];倒着选[last()],[last()-1]
- 选取一部分 1-3:[position()<4];5-最后: [position()>4]
-
xpath包含
//div[contains(@class,'i')]
class中包含i的div标签
lxml库使用
- 导入: from lxml import etree
- 转成element类型:
- html = etree.HTML(text)
- 查看element对象中包含的字符串:
- etree.tostring(html).decode()
- xpath方法
- html.xpath(“xpath语法”)
- 结果是列表,如果写错了就是空列表
- html.xpath(“xpath语法”)
lxml使用注意点
- lxml能够修正html代码,但是可能该错了
- 使用etree.tostring观察修改之后的html的样子,根据修改之后的html字符串写xpath
- 使用xpath返回的结果为列表
- 提取页面数据的思路:
- 先分组,取到一个包含分组标签的列表
- 遍历,取其中的每一组,进行数据的提取,不会造成数据的对应错乱
- lxml能够接受bytes和str的字符串
实现爬虫的套路
-
准备url
- 准备start_url
- url 地址规律不明显,总数不确定
- 通过代码提取下一页的url
- xpath
- 寻找url地址,部分参数在当前的响应中(比如当前页码数和总的页码数在当前响应中)
- 准备url_list
- 页码总数明确
- url地址规律明显
- 准备start_url
-
发送请求获取响应
- 添加随机的User-Agent,反反爬虫
- 添加随机的代理ip,反反爬虫
- 在对方判断出我们是爬虫后,应该添加更多的headers字段,包括cookie
- cookie的处理可以使用session来解决
- 准备一堆能用的cookie,组成cookie池
- 如果不登录
- 准备刚开始能够成功请求对方网站的cookie,即接受对方网站设置字啊response的cookie
- 下一次请求的时候,使用之前的列表中的cookie来请求
- 如果登录
- 准备多个账号
- 使用程序获取每个账号的cookie
- 之后请求登录之后才能访问的网站随机的选自cookie
- 如果不登录
-
提取数据
- 确定数据的位置
- 数据在当前的url地址中
- 提取列表页的数据
- 直接请求列表页的url地址,不用进入详情页
- 提取详情页的数据
- 1.确定url地址
- 2.发送请求
- 3.提取数据
- 4.返回
- 提取列表页的数据
- 如果数据不在当前的url地址中
- 在其他的响应中,寻找数据的位置
- 1.从network中从上往下找
- 2.使用chrome中的过滤条件,选择出了js,css,img之外的按钮
- 3.使用chrome的searcn all file,搜索数字和英文
- 在其他的响应中,寻找数据的位置
- 数据在当前的url地址中
- 数据的提取
- xpath,从html中提取整块的数据,先分组,之后每一组提取数据
- re,提取max_time,price,html中的json字符串
- json,json.dumps(),json.loads()
- 确定数据的位置
-
保存
- 保存在本地,text,json,csv
- 保存在数据库
队列
-
导入:
from queue import Queue
-
判断当前队列数据是否是空的
- Queue.empty() true/false
-
判断当队列是否是满的
- Queue.full() true/false
-
获取队列中的数据
- Queue.get()
- 一直从中取,直到取到数据,有超时参数,超时报错
- Queue.get_nowait()
- 直接取数据,不等待,队列为空的时候会报错
- Queue.get()
-
向队列中放数据
- Queue.put() - 会使队列数+1
- Queue.put_nowait()
- 不等待,直接放,队列为满的时候报错
-
获取队列中保存的个数
- Queue.qsize()
-
告诉主线程,让其等待子线程结束再结束
- Queue.join()
- 即:所有队列数为空时结束
-
队列数减一:
- 要配合这两个一起使用,如下
- Queue.get()
- Queue.task_done() – 如果不使用这个队列不会终止
- 才会队列数才会减一
-
将子线程设置为守护线程,该线程不重要主线程结束,子线程结束
- t.setDaemon(True)