爬虫相关基础知识

14 篇文章 0 订阅
8 篇文章 0 订阅

摘自《Python3网络爬虫开发实战》 崔庆才著

1、cookie和session都用来保存状态信息,都是保存客户端状态的机制,他们都是为了解决HTTP无状态的问题所做的努力。对于爬虫开发来说,我们更关注的是cookie,因为cookie将状态保存在客户端,session将状态保存在服务器端。
cookie是服务器在本地机器上存储的小段文本并随没一个请求发送至同一个服务器。网络服务器用HTTP头向客户端发送cookie,浏览器则会解析这些cookie并将它们保存为一个本地文件,它会自动将同一个服务器的任何请求绑定上这些cookie。
cookie的工作方式:服务器给每个session分配一个唯一的jsessionid,并通过cookie发送给客户端。当客户端发起新的请求的时候,将在cookie头中携带这个jsessionid。这样服务器就能够找到这个客户端对应的session。
2、get与post
get:是以实体的方式得到由请求URL所指定资源的信息,如果请求URL只是一个数据产生过程,那么最终要在响应实体中返回的是处理过程的结果所指向的资源,而不是处理过程的描述;
post:用来向目的服务器发送请求,要求它接受被附在请求后的实体,并将它当做请求队列中请求URL所指定资源的附加新子项。
区别:
在客户端,get方式通过URL提交数据,数据在URL中可以看到;post方式,数据放置在实体区内提交;
get方式提交的数据最多只有1024字节,而post则没有此限制;
安全性问题,使用get的时候,参数会显示在地址栏上,而post不会。根本上HTTPS还是比HTTP安全,因为加了一层验证。
3、增量式爬虫:对已下载网页采取增量式更新和只爬行新产生的或者已经发生变化网页的爬虫,它能够在一定程度上保证所爬行的页面是尽可能新的页面。能有效的减少数据下载量,及时更新已爬行的网页,减小时间和空间上的耗费,但是就会增加爬行算法的复杂度和实现难度。
表层网络指的是传统搜索引擎可以搜索的页面,以超链接可以到达的静态页面为主构成的web页面。
深层网络是那些大部分内容不能通过静态链接获取的、隐藏在搜索表单后的,只有用户提交一些关键词才能获取的web页面;例如用户登录或注册才能访问的页面;
4、r = requests.get(url)
r.content>>>返回的是字节形式
r.text>>>返回的是文本形式
r.encoding>>>返回的是根据HTTP头猜测的网页编码格式
5、重定向
就是通过各种方法将各种网络请求重新定个方向转到其它位置(如:网页重定向、域名的重定向、路由选择的变化也是对数据报文经由路径的一种重定向)。
6、不要在Elements选项卡直接查看源码,因为那里的源码可能经过JavaScript操作而与原始请求不同,而是需要从Network选项卡部分查看原始请求得到的源码。

7.关于爬虫中正则表达式为什么采用费贪婪模式,因为要取得最靠近的字符,保证准确性,采用贪婪模式意味着中间即便有符合条件的字符串也会被忽略,取得的是满足要求的最后一个字符。
8、解析库:lxml、BeautifulSoup、pyquery
9、xpath常用规则:
返回的是列表类型,每个元素是Element类型
nodename:选取此节点的所有子节点
/:从当前节点选区直接子节点
//:从当前节点选取子孙节点
.:选取当前节点
…:选取当前节点的父节点
@:选取属性
示例如下:

//title[@lang='eng']

代表选择所有名称为title,同时属性lang的值为eng的节点;
//li/a
代表选择所有li节点的所有直接a子节点
知道子节点,查询父节点:

'//a[@href="link4.html"]/../@class'

选中href属性为link4.html的a节点,然后选取器父节点的lass属性值
属性匹配

'//li[@class="item-0"]'

限制class属性值为item-0的li节点。
文本获取

'//li[@class="item-0"]/a/text()'

选取了属性为item-0的li节点的直接子节点a的文本
属性获取

'//li/a/@href'

获取所有li节点下所有a节点的href属性
属性多值匹配:多用于某个节点的某个属性有多个值
//li[contains(@class,"li")]/a/text()'
通过contains方法:第一个参数传入属性名称,第二个参数传入属性值
多属性确定一个值

'//li[contains(@class,'li')' and @name="item"]/a/text()'

class含有li以及name=item的所有li节点下的a节点的文本

按序选择:

li[1]:选择第一个li节点
li[last()]:选择最后一个li节点
li[position()<3]:选择位置小于3的节点
li[last()-2]:选择倒数第三个节点

节点轴选择:

'//li[1]/ancestor::*'

返回结果是第一个li节点的所有祖先节点

'//li[1]/ancestor::div'

返回的是div的祖先节点

'//li[1]/attribute::*'

li节点的所有属性
10、etree模块可以自动修正HTML文本
11、使用Beautiful Soup
借助网页的结构和属性等特性来解析网页,可以省去很多繁琐的提取工作,提高解析效率。

12、提取信息

soup = BeautifulSoup(html,'lxml')

解析器类型为lxml,这里是完成了BeautifulSoup对象的初始化,此时会对格式进行自动修正并补齐。
节点选择器
soup.title>>>title节点以及里面的文字内容
type(soup.title)>>>bs4.element.Tag类型
并且如果这种选择能找到多个节点时,只选择第一个匹配的节点
(1)获取属性
soup.p.attrs>>>返回字典形式的p标签下的所有属性+值
soup.p.attrs['name']>>>p标签下的name属性对应的值 等价于 soup.p[‘name’],对应的类型需要加以判断
(2)获取内容

soup.p.string

第一个p节点的文本内容
嵌套选择

soup.head.title

head标签下的title标签的标签+内容
返回类型还是Tag类型
关联选择

soup.p.contents

p节点内的全部内容,包括文本与节点,最终将它们以列表的形式进行返回。

soup.a.parent

a节点的直接父节点,输出结果是标签+内容
parents则返回所有的祖先节点
兄弟节点

soup.a.next_sibling

下一个兄弟节点

soup.a.previous_sibling

上一个兄弟节点

soup.a.next_siblings、soup.a.previous_siblings

返回前面和后面的所有兄弟节点的生成器

提取信息:
如果返回的是单个节点,可以使用string、attrs等属性获取文本和属性;
如果返回的是多个节点的生成器,则可以转为列表后取出某个元素,然后再调用string、attrs等属性获取其对应节点的文本和属性。

13、方法选择器

soup.find_all(name='ul')

查询所有ul节点,返回结果是列表类型,每个元素是Tag类型

soup.find_all(attrs={'id':"list-1"})

查询id为list-1的节点元素

soup.find_all(text=re.compile('link'))

返回所有匹配正则表达式的节点文本组成的列表
find()返回的是单个Tag类型的元素、find_all()返回的是所有匹配元素组成的列表
14、css选择器
使用CSS选择器时,只需要调用select()方法,传入相应的CSS选择器即可,返回的仍然是tag类型元素组成的列表

soup.select('.panel .panel-heading')

soup.select('ul li')-->所有ul节点下的所有li节点
每个Tag都可以获取属性,['id']/attrs['id']
获取文本:.get_text()/.string

15、总结
(1)推荐使用lxml解析库,必要时使用html.parser
(2)节点选择筛选功能弱但是速度快
(3)建议使用find()或者find_all()查询匹配单个结果或多个结果
(4)如果对CSS选择器熟悉的话,可以使用select()方法选择。

16、使用pyquery
字符串初始化:
引入PyQuery这个对象:from pyquery import PyQuery as pq
将html作为参数传递给PyQuery这个类,完成初始化:doc = pq(html)
这里的初始参数不仅可以传递字符串,还可以传入网页的URL,指定参数为url即可:doc = pq(url='http://www.baidu.com')
等价于doc = pq(requests.get('http://www.baidu.com').text)
还可以传递本地文件名,指定参数为filename即可:doc = pq(filename='demo.html')
这里需要有一个本地文件demo.html,其内容是待解析的HTML字符串
打印输出所有的li节点:print(doc('li'))

17、基本的CSS选择器
doc('#container .list li')–>先选取id为container的节点,然后再选取其内部的class为list的节点内部的所有li节点。返回类型是PyQuery类型
查找节点
items = doc('.list')–>class为list的节点
items.find('li')–>选取其内部的li节点
items.children('.active')–>筛选出子节点中class为active的节点
doc('.list').parent()–>选择class为list的节点,然后调用parent()方法得到其直接父节点,返回类型是PyQuery类型;调用parents()得到的是祖先节点,
parents().('.wrap')–>祖先节点中的class为wrap的节点

18、遍历
需要调用items()方法:

doc=pq(html)
lis=doc('li').items()
for li in lis:
    print(li)

可以发现,调用items()方法后,会得到一个生成器,遍历一下,就可以逐个得到li节点对象了,它的类型也是PyQuery类型。

19、获取信息
(1)获取属性:attr()

a = doc('.item-0.active a')
a.attr('href')

首先选中class为item-0和active的li节点内的a节点,它的类型是PyQuery类型,然后调用attr()方法,在方法中传入属性的名称,就可以得到属性值。这里找的是href的属性值。也可以写成a.attr.href
当返回的结果包含多个节点时,调用attr()方法,只会得到第一个节点的属性,解决这种情况:

for item in a.items():
  print(item.attr('href'))

因此在进行属性获取时,可以观察返回节点是一个还是多个,如果是多个,则需要遍历才能依次获取每个节点的属性。
(2)获取文本
获取节点之后的另一个主要操作就是获取其内部的文本了,此时可以调用text()方法来实现:

a = doc('.item-0.active a')
a.text()

这首先选中了一个a节点,然后调用text()方法,就可以获取其内部的文本信息。此时它会忽略掉节点内部包含的所有HTML,只返回纯文字内容。
但如果想要获取这个节点内部的HTML文本,就要用html()方法了:

a = doc('.item-0.active a')
a.html()

对应a节点内的所有HTML文本
如果我们选中的结果是多个节点, text ()或 html ()会返回什么内容?
结果可能比较出乎意料,html()方法返回的是第一个li节点的内部HTML文本,而text()则返回了所有的li节点内部的纯文本,中间用一个空格分割开,即返回结果是一个字符串。
所以这个地方值得注意,如果得到的结果是多个节点,并且想要获取每个节点的内部HTML文本,则需要遍历每个节点。而text()方法不需要遍历就可以获取,它将所有节点取文本之后合并成一个字符串。

20、节点操作
这里说几个比较重要的:addClass()和removeClass()可以动态改变节点的class属性

a = doc('.item-0.active a')

a.removeClass('active')–>这里将节点中的active这个class移除
a.addClass('active')–>又把这个class加上去

attr():传一个参数则获取该属性的值;如果传入第二个参数,则可以用来修改属性值,没有则添加;
text():不传参,则获取文本;传参则替代原文本
html():不传参,则获取文本;传参则替代原来的html

remove()
doc = pq(html)
wrap = doc('.wrap')
wrap.find('p').remove()

选中p节点,然后调用remove()方法将其移除

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值