在进行Python爬虫解析时,需要注意以下事项:
1、良好的网站使用协议:需要遵守网站的robots.txt文件,以确保你的爬虫程序不会将网站拦截下来。
2、编码问题:需要正确设置HTTP头和解析器的编码,以确保爬虫程序能够正确地解析网站的信息。
3、数据解析:需要适当地处理HTML文档中的标签,以便从中筛选出目标数据。
4、网站反爬虫机制:需要了解网站的反爬虫机制,采取相应的策略,确保爬虫程序不会被网站屏蔽。
5、频率控制:需要适度控制爬虫程序的请求频率,以避免给网站带来过多负荷。
6、数据存储:需要将爬取到的数据存储到合适的位置,例如数据库或文件系统中。
7、长期稳定性:需要优化代码,确保程序长期稳定地工作。
今天主要整理python的三种解析方法
正则表达式
1、正则解析主要是以//.和//.?的两种从而获得想要获取的数据就比如说在分页爬取的时候中间的
ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
img_src_list = re.findall(ex, page_text, re.S)
这是一个正则表达式的一个解析式 中间的(.*?)就是用来匹配你所要的内容。
主要就是是用python所提供的re模块用于实现正则表达式的操作,在操作的时候可以使用re提供的方法(search(),match(),findall())进行字符串处理;
他们三个都有共同的参数
pattern:模式字符串
string:要进行匹配的字符串
flags:可选参数,表示标识位,用于控制匹配方式,如是否匹配字母大小写
match()
用于从字符串的开始位置进行匹配如果开始位置匹配成功择返回match对象,否则择返回None
search()
用于整个字符串中搜索第一个匹配到的值,如果匹配成功则返回search对象,如果没有匹配成功则返回None
findall()
用于匹配整个列表中所有符合正测表达式的字符串并一列表的形式返回,,没有则返回None
关于.和.?的区别
.表示匹配换行符之外的任何单字符,*表示零次或者多次,所以.和在一起就是表示出现任意字符零次或者多次。如果没有?则表示贪婪模式
比如 a.b他将会匹配最长的以a开始,以b结束的字符串
.?表示懒惰模式
比如a.?b将会匹配以a开始,以b结束匹配最短的且符合标准的字符串
# 分页爬取
import requests
import os
import re
if __name__ == '__main__':
if not os.path.exists('./fenyelibs'):
os.mkdir('./fenyelibs')
else:
print()
# 设置一个通用的url模版
url = 'https://www.qiushibaike.com/imgrank/page/%d/'
# pagenum=2
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36 Edg/90.0.818.51'
}
for item in range(1, 3):
pagenum = item
new_url = format(url % pagenum)
# print(new_url)
page_text = requests.get(url=new_url, headers=headers).text
ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
img_src_list = re.findall(ex, page_text, re.S)
for src in img_src_list:
new_src = 'https:' + src
img_data = requests.get(new_src, headers=headers).content
img_name = src.split('/')[-1]
img_path = './fenyelibs/' + img_name
with open(img_path, "wb")as file:
file.write(img_data)
print(img_name, '下载完成')
print('下载完成!!!')
bs4解析
# 针对与bs4 实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中
# 通过调用BeautifulSoup对象中相关的属性或者办法进行标签定位
from bs4 import BeautifulSoup
if __name__ == '__main__':
fp = open('./text.html', 'r', encoding='utf-8')
soup = BeautifulSoup(fp, 'lxml')
#print(soup)
print(soup.a)#soup.tagname 返回的是HTML中第一次出现的tagname对应的标签
print('-----')
print(soup.div)
#soup.find()
print('------')
print(soup.find('div'))#相当于soup.div
#属性定位
print('---------属性定位:\n',soup.find('div',class_='song'),'\n')
print('--------find_all:',soup.find_all('a'))
#select
print('----select\n',soup.select('.tang'),'\n')#某种选择器(id,class,标签...选择器),返回的是一个列表 只要符合选择器的要求
#层级选择器
print(soup.select('.tang > ul > li > a')[0],'\n')#>是一个层级
print(soup.select('.tang > ul a')[0])#空格表示多个层级
#获取标签之间的文本数据 text 和get_text()可以获取标签中的所有文本内容
# string只可以获取该标签下面的直系文本内容
print(soup.select('.tang > ul a')[0].get_text())
print(soup.select('.tang > ul a')[0].text)
print(soup.select('.tang > ul a')[0].string,'\n')
print('测试一下','\n')
print(soup.find('div',class_='song').text)
#获取标签中的属性值'
print('获取标签中的属性值:\n',soup.select('.tang>ul a')[0]['href'])
他这中间会有find find_all select 三种查找的犯法
find是返回查找到的第一个值
find_all是返回查找到的所有值以列表形式返回
select 某种选择器(id,class,标签…选择器),返回的是一个列表 只要符合选择器的要求
他在进行网页查找的时候要记得在他div的标签属性下加.使用>进行下一个选项如果要跨级去中的话那就要是用空格
xpath解析
from lxml import etree
import requests
if __name__ == '__main__':
print('hello python!!')
#实例化一个etree对象,并且被解析的源码也加载到了该对象中
tree=etree.parse('text.html')
#调用xpath
r=tree.xpath('/html/body/div/text()')#在HTML前边加一个/标识从根节点开始 后边的/标识一个层级
# r=tree.xpath('/html//div')#//表示多个层级
#r=tree.xpath('//div')#//标识可以从任意的位置去定位div标签
print(r)
# r1 = tree.xpath('//div[@class="sng"]/p[3]')
# r2 = tree.xpath('//div[@class="sang"]/p[3]') # 索引是从1开始的
# # print(r1)
# print(r2)
r3=tree.xpath('//div[@class="tang"]//li[5]/a/text()')[0]#取文本用/text()
print(r3)
r4=tree.xpath('//li[7]//text()')[0]#/txet()获取的是标签中直系的文本内容
#//text()获取的是标签中的非直系的内容
print(r4)
r5=tree.xpath('//li//text()')
for item in r5:
print(item)
print('----------------')
r6=tree.xpath('//div[@class="sang"]/img/@src')#取属性值用/@sttrName 可以取到标签属性当中的文本内容
print(r6)
这个他就使用的是/进行分级的 要是要想跨级进行查找的话那就要使用//