基本爬虫方法手册

发布时间 2023-12-18 09:32:52作者: CloudWk

一、requests库方法(部分)

1、会话维持

​ 在Python爬取页面时,有一些页面需要登录才能访问,requests库中有两种方式可以解决这个问题。

# 第一种方式Cookie
import requests

headers = {
    'Cookie':'....',
    'Host':'....',
    'User-Agent':'.....'
}
resp = requests.get('http://www.xxx.com', headers=herders) # 携带上所需要的Cookie即可
print(resp.text)

# 第二种方式Session
import requests

headers = {
    'Cookie':'实际字段',
    'Host':'',
    'User-Agent':''
}
session = requests.Session() # 后续使用session变量名用于保持Cookie传递
# 和设置Cookie相比这种方式的好处是,后续请求不需要携带headers字段
resp = session.get('http://www.xxx.com', headers=herders) 
resp_test = session.get('http://www.xxx.com/pag') # Ps:后续不需要携带headers字段,也可保持Cookie的传递。
print(resp.text)

2、代理

​ 网站对于请求频繁的IP可能会弹出验证码,或者跳转登录页面,也可能会直接封禁客户端的IP,这时候就要用到代理。

import requests

proxies = {
    'http':'http://10.10.1.10:3128',,
    'https':'https://10.10.1.10:1080'
}
requests.get('https://taobao.com', proxies=proxies)
# 有些网站由于没有安全证书会弹出不是私密连接
response = requests.get('http://xxx.com', verify=False) # 通过verify设置为False不验证证书
# 设置timeout请求等待响应超时的时间
response = requests.get('http://xxx.com', timeout=1)

3、Prepared Request

​ 在requests库中还可以使用Request对象来独立请求,可以将请求当作独立的对象看待,在进行队列调度时会非常方便,用法如下:

from requests import Request, Session

url = 'http://xxx.com'
s = Session()
req = Request('POST', url) # 里面可以加上data、headers等参数
prepped = s.prepare_request(req) # 通过Session这个方法将Request对象转换为Prepared Request对象
r = s.send(prepped) # 发送请求
print(r.text)

二、re库正则表达式(部分)

​ 正则表达式用于爬虫的HTML提取解析非常方便,通过Python中的re模块就可以非常方便的提取所需要的数据。

1、re.match函数(开头匹配:一般用于检查某个字符串是否符合正则匹配)

​ 语法:re.match(pattern, string, flags=0)

pattern string
匹配的正则表达式 要匹配的字符串

flags(修饰符):

  1. re.I 忽略大小写
  2. re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
  3. re.M 多行模式
  4. re.S 即为 . 并且包括换行符在内的任意字符(由于. 不包括换行符),常用于匹配换行的字符串。
  5. re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
  6. re.X 为了增加可读性,忽略空格和 # 后面的注释
import re

result = re.match("itcast","itcast.cn")
result.group()
>>>'itcast'

# 第二种使用方法group(1),括号代表分组
content = 'Hello 123456 World_This is a Regex Demo'
result = re.match('Hello\s(\d+)\sWorld', content)
print(result.group())
>>> 'Hello 123456 World'
print(result.group(1)) # 提取分组里面的内容
>>>'123456'

2、贪婪与非贪婪

​ 贪婪与非贪婪匹配差别是:.*(贪婪模式)会尽可能多的去匹配字符;非贪婪模式即在贪婪模式后面加上?匹配尽可能少的字符串,在做匹配时,字符串中间尽可能使用非贪婪模式匹配,以免出现匹配结果缺失的情况。

3、search方法(全量匹配)

​ match()方法是从字符串的开头匹配的,一旦开头不匹配,整个匹配就不能成功。

import re 

content = 'Exce Hello 121'
result = re.match('Hello.*', content)
result = re.search('Hello.*', content, re.S) # re.S可以匹配换行
print(result)
>>> None        # match匹配结果
>>> 'Hello 121' # search匹配结果

4、findall方法(全局匹配)

​ search方法可以返回匹配的第一个结果,但是在实际爬虫中,我就是需要多个匹配返回结果怎么办呢?这时候就需要借助到findall函数方法了,这个方法会返回正则表达式匹配的所有结果。

import re
pattern=r'mr_\w+'
string='MR_SHOP mr_shop'
match=re.findall(pattern,string,re.I)
print(match)
>>>['MR_SHOP', 'mr_shop']
for ma in match:
    print(ma) # 循环打印匹配的结果,可以用列表索引取值ma[1]

5、sub方法(替换)

​ 如果是为了替换一部分字段,或者替换为空值,使用字符串的replace方法太繁琐了,可以借助sub方法匹配替换。

import re

content = '32aKds3l3e32reva'
result = re.sub('\d+', '', content)
print(result)
>>> 'aKdslereva'

6、compile方法

​ 这个方法主要是将正则匹配规则编译为表达式对象,方便在后面的正则表示式匹配中去复用。

import re

content1 = '2023-12-23 15:00'
content2 = '2023-2-5 12:00'
pattern = re.compile('\d{2}:\d{2}') # 可以在后面加上修饰符,这样后面的就不需要加上修饰符了
result1 = re.sub(pattern, '', content1)
result2 = re.sub(pattern, '', content2)
print(result1, result2)
>>> '2023-12-23'
>>> '2023-2-5'

7、常用的正则匹配规则(部分)

描述 模式
\w 匹配字母、数字及下划线
\s 匹配任意空白字符,等价于[\t\n\r\f],即匹配换行符、制表符等
\d 匹配任意数字,等价于[0-9]
. 匹配任意字符,除了换行符,若指定re.S,则可以匹配到包括换行符的任意字符
* 匹配前面0个或者多个表达式
+ 匹配前面一个或多个表达式
? 匹配0个或1个前面的正则表达式定义的片段,非贪婪模式
精确匹配到n个前面的表达式
( ) 提取匹配括号内的表达式,也表示为一个组

三、Xpath解析

​ xpath常用匹配规则如下表所示:

表达式 描述
nodename 选取此节点的所有子节点
/ 从当前节点选取直接子节点
// 从当前节点选取子孙节点
. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性

1、lxml库运用(部分)

​ 在Python中使用Xpath可以使用lxml这个库来匹配网页中的各个节点,lxml不但能匹配HTML文档还能匹配XML文档,当然还能创建XML文档,这里只对运用HTML文档的匹配进行说明。

from lxml import etree

html = etree.parse('./test.html', etree.HTMLParser()) # (1)读取本地文本文件进行解析
ewsult = html.xpaht('//li/a')
print(result)

text = '''
<li class="li li-first" name="item"><a href="link.html">first item</a></li>
................
''' 
html = etree.HTML(text) # (2) 通过HTML类对爬取的网页进行初始化
result = html.xpath('//li[@class=li li-first]/a')
result = html.xpath('//li[1]/a/text()') # li[1]通过索引获取指定次序的节点,text()匹配文本
result = html.xpath('//li[last()]/a/text()') # last()匹配排名最后li节点,last()-2用于匹配倒数第三个节点
result = html.xpath('//li[position()<3]/a/text()') # position()<3匹配位置小于3的li节点,即1和2
# -----------------------------------------
result = html.xpath('//li[1]/ancestor::*') # ancestor::*轴用于获取双冒号后面规则的祖先节点
result = html.xpath('//li[1]/attribute::*') # attribute::*轴用于双冒号后面规则:获取li节点的所有属性
result = html.xpath('//li[1]/child::a[@herf="link.html"]') # child轴获取直接子节点,获取属性为herf="link.html"的a子节点
result = html.xpath('//li[1]/parent::*') #parent::*轴选取父节点。 

四、Beautiful Soup解析库运用(部分)

​ Beautiful Soup库是一个通过网页的结构和属性等特性来解析网页。通过它可以不用去写一些复杂的正则表达式,只需要简单几条语句,就可以完成对网页的某个元素的提取。

解析器 使用方法 优势
Python标准库 BeautifulSoup(html, “html.parser”) 1、Python的内置标准库
2、执行速度适中
3、文档容错能力强
lxml HTML解析器 BeautifulSoup(html, “lxml”) 1.速度快
2.文档容错能力强
lxml XML解析器 BeautifulSoup(html, [“lxml”, “xml”]) BeautifulSoup(html, “xml”) 1.速度快
2.唯一支持XML的解析器
html5lib BeautifulSoup(html, “html5lib”) 1.最好的容错性
2.以浏览器的方式解析文档
3.生成HTML5的文档

Ps:一般用于爬虫来解析HTML网页用的是第一个和第二个方法。

1、基本用法

from bs4 import BeautifulSoup

# 1、基本用法----------------------------------------------------
soup = BeautifulSoup(html, "lxml") # 用lxml HTML解析器解析速度快一些,用html.parser也没问题。
print(soup.prettify()) # 把需要解析的字符串一标准格式缩进输出
print(soup.title.string) # 通过title方法提取title节点和文本内容,通过string得到里面的文本
# 2、节点选择----------------------------------------------------
print(soup.div)
# >>> <div class="..." id="...">.........</div>
print(soup.head, soup.p) # 直接(.节点名)可以直接获取节点即里面的属性和文本
# 3、提取信息----------------------------------------------------
# (1)获取节点名称
print(soup.title.name) # 通过name属性获取节点名:title
# (2)获取属性attrs方法
print(soup.p.attrs) # 通过attrs获取属性
print(soup.p.attrs['name'])
'''
>>> {'class':['title'], 'name':'dromouse'}
>>> dromouse
'''
# (2)获取属性不使用attrs简单方法
print(soup.p['name'])
print(soup.p['class'])
'''
>>> dromouse
>>> ['title']
返回值不一样是由于class属性值不具有唯一性,一个节点可以有多个class属性值,name值唯一。
'''
# (3)嵌套选择
pirnt(soup.head.title.string)
# (4)关联选择(由于多个节点嵌套)
print(soup.p.contents)
# >>> 输出p节点的直接子节点宜列表输出。

2、方法选择器

from bs4 import BeautifulSoup
import re

soup = BeautifulSoup(html, "lxml")
# (1)find_all()方法:返回所有匹配到的元素列表———————————————————————————————————
print(soup.find_all(name='li')) # 不写name关键字也行
# >>> 输出的结果为所有的li标签,返回值类型为列表

for ul in find_all(name='ul'):
    print(ul.find_all(name='li'))
# >>> 输出的结果为ul标签下的li标签(嵌套)

print(soup.find_all(attrs={'id':'list-1'}))
print(soup.find_all(attrs={'name':'elements'})
print(soup.find_all(id='list-1')) # 常用的如id、class属性,不需要通过attrs传递
print(soup.find_all(clss_=' element'))
# >>> 输出结果为列表类型的、属性为指定属性的节点

print(soup.find_all(text=re.compile('link'))) # 匹配节点的文本,text的值可以是文本和正则表达式
# >>> 输出结果为['str', 'str'],Ps:一般不常用。

# (1)find()方法:返回第一个匹配到的元素-------———————————————————————————————————
print(soup.find(name='ul'))
print(soup.find(class_='element'))
# >>> 结果不再是列表类型,而是第一个匹配到的节点元素。

还有其他方法选择器,,用法与上面两种一样,只是查询的范围不同,下面简单说明一下:

  • find_parents( )和find_parent( ):前者返回所有的祖先节点,后者返回直接父节点。
  • find_next_siblings( )和find_previous_sibling( ):前者返回前面所有的兄弟节点,后者返回前面第一个兄弟节点。
  • find_all_next( )和find__next( ):前者返回节点后所有符合条件的节点,后者返回第一个符合条件的节点。
  • find_all_previous( )和find_previous( ):前者返回节点前所有符合条件的节点,后者返回第一个符合条件的节点。

3、CSS选择器

​ 使用CSS选择器只需要调用select( )方法,传入相应的CSS选择器即可,示例如下:

from bs4 import BeautifulSoup

soup = BeautifulSoup(html, 'lxml')
# (1)基本用法————————————————————————————————————
print(soup.select('.panel .panel-heading'))
print(soup.select('ul li'))
print(soup.select('#list-2 .element'))
# (2)嵌套选择————————————————————————————————————
for ul in soup.select('ul'):
    print(ul.select('li'))
# (3)获取属性值————————————————————————————————————
for ul in soup.select('ul'):
    print(ul['id'])
    print(ul.attrs['id'])
    print(ul.get('src'))
# (4)获取文本————————————————————————————————————
for li in soup.select('li'):
    print(li.get_text())
    print(li.string)

五、pyquery库(部分)

​ 虽然Beautiful Soup的CSS选择器已经很好了,但是还是有另外一种使用CSS选择器来解析的库,而且相比起来非常好用。

​ 和Beautiful Soup一样,初始化pyquery的时候,也是需要传入一个HTML文本来初始化一个PyQuery对象。它的初始化方法有很多,比如直接传入字符串、传入URL,传入文件名等等。

1、初始化

from pyquery import PyQuery as pq

html = '''
<div>
	<span>...</span>
	<li>...</li>
	<li>...</li>
	<li>...</li>
</div>
'''
# (1)字符串初始化————————————————————————————
doc = pq(html)
print(doc('li')) # 返回所有的li标签
# (2)URL初始化———————————————————————————————
doc = pq(url='http://www.xxx.com')
print(doc('title')) # 返回网站title标签
doc = pq(requests.get('http://www.xxx.com').text) # 与上面的字符串初始化方法是一样的
print(doc('title')) # 返回网站title标签
# (3)文件初始化——————————————————————————————
doc = pq(filename='demo.html')
print(doc('title'))

2、基本CSS选择器

from pyquery import PyQuery as pq

doc = pq(html)
print(doc('#container .list li'))
# >>> 输出id为container内部class为list下内部的li节点
# (1)查找子孙节点:find()方法————————————————————————————————————
items = doc('.list')
lis = items.find('li')
print(lis)
# >>> 选取class为list的节点,然后选择其子节点li节点
lis = items.children() # children值查找符合条件的子节点,find则是查找符合条件的子孙节点
# (2)查找父节点:parent()方法————————————————————————————————————
doc = pq(html)
items = doc('.list')
container = items.parent()
print(container) # 通过找到class为list的节点,然后使用parent()找到其直接父节点
# parents()方法则是用来找到其祖先节点
# (3)查找兄弟节点:siblings()方法,用法同上——————————————————————————
# (4)遍历:items()方法—————————————————————————————————————————————
lis = doc('li').items()
for li in lis:
    print(li)
# (5)获取属性,通过attr()方法———————————————————————————————————————
a = doc('a')
print(a.attr('href'))
print(a.attr.href) # 两种方法都能获取到属性,但是只能获取到一个
for item in a.items():
    print(item.attr('href')) # 通过遍历方法就能同时获取到多个属性
    
# (6)获取文本:text()、html()方法————————————————————————————————————————————
a = doc('.item-0.active a')
print(a.text())
print(a.html())
# 它们之间的区别就是text()用于获取标签夹带的文本,html()则获取a下面的标签节点。

3、节点操作(部分举例)

​ pyquery提供了一系列方法来对节点进行动态修改,比如为某一个节点添加一个class,移除某个节点等。

  • addClass和removeClass
from pyquery import PyQuery as pq

html = '<div>........</div>'
doc = pq(html)
li = doc('.item-0.active')
print(li)
li.removeClass('.active')
print(li)
li.addClass('.active')
print(li)
'''
三次打印的结果如下:
<li class="item-0 active">.....</li>
<li class="item-0">.....</li>
<li class="item-0 active">.....</li>
'''
# addClass和removeClass方法可以动态改变节点的class属性。
# 当然,除了操作class属性外,也可以用attr()方法对属性进行操作。还可以用text()和html()
li = doc('.item-0.active')
li.attr('name', 'link') # 对节点添加name属性,值为link
li.text('changed item') # 对节点内的内容改变为changed item
li.html('<span>changed item</span>') # 在节点内部添加标签
# attr()传递一个参数用于获取属性,两个参数则是修改。text()、html()传递参数则是用于赋值。
  • remove()方法
doc = pq(html)
wrap = doc('.wrap')
wrap.find('p').remove()
print(wrap.text())
# 这个方法主要是为了更加方便的提取指定参数值,把多余的节点进行删除,方便提取想要的节点。

4、伪类选择器(部分)

​ CSS选择器之所以强大,一个非常重要的原因就是它支持多种多样的伪类选择器,例如选择第一个节点、最后一个节点、奇偶数节点等等。

from pyquery import PyQuery as pq

html = '<div>.....</div>'
doc = pq(html)
li = doc('li:first-child') # 选择第一个li节点
li = doc('li:last-child') # 选择最后一个li节点
li = doc('li:nth-child(2)') # 第二个li节点
li = doc('li:gt(2)') # 第三个之后的li节点、-n)B=u9-'80y