提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、requests模块
作用:模拟浏览器发送请求
response = requests.get(url,params,headers)
response = requests.post(url,data,headers)
url:ip地址
params:参数字典 (在访问url时动态拼接了params)
headers:用get方法发起请求所带的头信息是什么
data:与params用法一致
例:
url = 'https://www.baidu.com/s?'
params = {
'wd':'湖北'
}
response = requests.get(url,params,headers)
最后访问的页面为https://www.baidu.com/s?wd=湖北
常见反爬机制:UA检测:门户网站检测请求载体的身份标识
反反爬:UA伪装:让爬虫对应的请求载体身份标识为某一浏览器
做法:
headers = {'User-agent':'F12粘贴请求标头'}
注:如果页面URL没有发生变化,而页面的局部刷新了或变化就很可能是ajax请求,一些页面数据是动态加载出来。
对于ajax异步加载的数据需要F12去看抓包工具找具体的url地址和请求所携带的表单数据
如:
有时候在headers中最下面的位置,有时候在Preview里
根据headers里面具体的请求方式[‘get’,‘post’]
选择是data还是params,以键值对的形式填写,得到响应的json数据
如:
url = 'xxxx'
data = {''params":"234ewdfsa"}
response = requests.post(url,data).json
数据的存储
如果是text文件 with open存储
如果json 用json.dump(obj(json的对象),fp(文件位置和名字),ensure_ascii=False)
with open("地址",'w',encoding='utf-8') as fp:
fp.write(page_text)
二、数据解析
原理:1、进行指定标签的定位。2、标签或标签对应的属性中存储的数据值进行提取(解析)。(因为:解析的局部的文本内容都会在标签之间或者标签对应的属性中进行存储)
1.bs4解析
1、实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中。2、通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取。
2、bs4进行解析的原理:1.标签定位。2.提取标签、标签属性中存储的数据值
3、具体步骤:1.实例化一个BeautifulSoup对象,并将页面源码数据加载到该对象中。2.通过调用BeautifulSoup对象中相关的属性或方法进行标签定位和数据提取
–环境安装:pip install bs4和lxml
——对象的实例化
—1、将本地的html文档中的数据加载到该对象中
fp = open('./test.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml') #lxml是解析器
-2 将互联网上获取的页面源码加载到对象中
page_text = response.text
soup = BeautifulSoup(page_text,'lxml')
-3 一些用于数据解析的方法和熟悉
#如上 soup为bs4实例化的一个对象
soup.a #soup.tagName返回的是html中第一次出现的tagName对应的标签 tagName:标签名
# find()函数的用法
soup.find('div') # 等同于soup.div
# 属性定位
soup.find('div',class_/id/attr='className') #找对应className属性的div标签,也可以查找别的属性值如:id
# find_all()
soup.find_all('a') # 拿到指定页面中所有的a标签 参数用法和find类似
#select() 可以选择指定的选择器 id、class...
# 如类选择器
soup.select('.className') # 返回一个列表,符合要求的数据
# 层级选择器
soup.select('.className > ul > li > a') : >表示一个层级
soup.select('.className > ul a') : 空格表示多个层级
# 获取标签之间的文本数据
soup.a.text == soup.a.string == soup.a.get_text() #获取第一个a标签的文本数据
soup.select('.className > ul a')[0].get_text()
三种方法的区别:
text/get_text():可以获取某一个标签中所有的文本内容
string:只可以获取该标签下直系的文本内容
# 获取标签中属性值
soup.a['属性名'] #如 soup.a['href']
-4 实战(爬取三国演义内容)
import requests
from bs4 import BeautifulSoup
from tqdm import tqdm
# 三国演义章节和内容
url = 'https://so.gushiwen.cn/guwen/book_46653FD803893E4F7F702BCF1F7CCE17.aspx'
headers = {
'F12'
}
response = requests.get(url=url,headers=headers).text
# print(response)
soup = BeautifulSoup(response,'lxml')
# print(soup)
a_list = soup.select('.bookcont > ul a')
title = []
content = []
fp = open('./data/sanguo.txt','w',encoding='utf-8')
for a in tqdm(a_list,desc='三国演义爬取中',total=120,ncols=100,mininterval=0.1):
detail_href = a['href']
detail_page = requests.get(url=detail_href,headers=headers).text
de_soup = BeautifulSoup(detail_page,'lxml')
detail_content = de_soup.find('div',class_='contson').text
detail_title = de_soup.select('.cont > h1')[0].get_text().replace('\n','') + de_soup.p.string.replace('\u3000',' ')
title.append(detail_title) # 去除字符
fp.write(detail_title+":"+detail_content+'\n')
print('爬取成功')
fp.close()
2.Xpath解析
-xpath解析原理
-1.实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中
-2.调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获
-环境安装:pip install lxml
-如何实例化一个etree对象:from lxml import etree
-1. 将本地的html文档中的源码数据加载到etree对象中 etree.parse(filePath)
-2. 可以将从互联网上火却的源码数据加载到该对象中 etree.HTML(‘page_text’)
- xpath(‘xpath表达式’)
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 表示的是从根节点开始定位。表示的是一个层级。 |
// | 表示的是多个层级。可以表示从任意位置开始定位。 |
. | 选取当前节点 |
… | 选取当前节点的父节点 |
@ | 选取属性 |
* | 通配符,选择所有元素节点与元素名 |
@* | 选取所有属性 |
[@attrib] | 选取具有给定属性的所有元素 |
[@attrib=‘value’] | 选取给定属性具有给定值的所有元素 |
[tag] | 选取所有具有指定元素的直接子节点 |
[tag=‘text’] | 选取所有具有指定元素并且文本内容是text节点 |
示例:
tree.xpath('/html/body/div') #直接从上往下挨着找节点
tree.xpath('/html//div')#跳跃了一个节点来找到这个div节点的对象
tree.xpath('//div')##跳跃上面所有节点来寻找div节点的对象
tree.xpath('//div[@class="className"]') # 寻找对应属性的div 返回符合要求的对象
tree.xpath('//div[@class="className"]/p[3]')
tree.xpath('//div[@class="className"]//li[5]/a/text()') #text()是把element转化为文本,当然上面的在后面加个text()都可以展示文本内容。返回的是一个列表
# 如果要取字符串
tree.xpath('//div[@class="className"]//li[5]/a/text()')[0]
# 取属性 可以直接用@取属性 如:
tree.xpath('//div[@class="className"]/img/@src') #返回的也是列表
-实战(爬取图片)
from lxml import etree
import requests
import os
# 为解决SSL错误的尝试
import urllib3
urllib3.disable_warnings()
url = 'https://pic.netbian.com'
headers = {
'F12'
}
#对网页发起请求
response = requests.get(url=url,headers=headers).text
#etree对象
tree = etree.HTML(response)
a_list = tree.xpath('//*[@id="main"]/div[3]/ul/li/a')
img_link = []
# 创建一个文件夹
if not os.path.exists('./data/picLibs'):
os.mkdir('./data/picLibs')
for a in a_list:
title = a.xpath('./@title')[0]
# 通用处理中文乱码的解决方案
title = title.encode('iso-8859-1').decode('gbk')
href = url + a.xpath('.//img/@src')[0]
print(title,href)
# 请求图片 进行持久化存储
try:
img_data = requests.get(url=href,headers=headers,verify=False).content #图片是二进制形式
img_path = './data/picLibs/' + title +'.jpg'
with open(img_path,'wb') as fp:
fp.write(img_data)
print(title,"下载成功")
except:
pass
总结
学习笔记记录,观看于B站路飞IT学城
https://www.bilibili.com/video/BV1Yh411o7Sz