爬虫笔记
一、爬虫使用场景分类
一、通用爬虫:
抓取系统的重要组成部分。抓取整个页面数据。
2.聚焦爬虫:
在建立再通用爬虫的基础上。抓取页面中特定的局部内容。
3.增量爬虫:
检测网站中的数据更新情况。在网站中捕获最新更新的数据。
了解概念:
反爬 通过制定相应的策略或技术手段,门户网站可以防止爬虫程序爬取网站数据。
反爬策略:
爬虫程序可以通过指定相关策略或技术手段破解门户网站的反爬机制,从而获取门户网站的相关数据。
robots.txt协议:
网站规定的协议规定了哪些信息可以被爬虫爬行。
二、常用协议
HTTP协议:
概念:是服务器与客户端数据交互的一种形式。
请求头常用信息:
~User-Agent:请求载体身份标识。
~Connection:请求完成后,是断开连接还是保持连接。
常用响应头信息:
~Content-Type:服务器响应客户端的数据类型。
HTTPS协议:
~安全的超文本传输协议,数据加密。
加密方式:
~对称密钥加密
~非对称密钥加密
~加密证书秘钥
三、requests模块
注:urllib模块繁琐,基本用法urllib模块代替。
概念:基于网络要求的模块,功能强大,简单方便,效率高。
功能:模拟浏览器头发请求。
环境安装:pip install requests
操作流程(requests模块编码流程)
1.指定url
2.发起请求
3.获取响应数据
4.持久存储
import requests if __name__== "__main__": #1.指定URL url = "https://www.sogou.com/"; #2.启动请求并保存响应数据respense中 response = requests.get(url= url); #3将respense中间的数据以文本形式保存 page_text = response.text; print(page_text); #4.持久存储,将爬行内容存储在网页上 with open("./sogou.html" , 'w' , encoding='utf-8') as fp: fp.write(page_text); print("运行结束!");
实战项目
搜索结果页面(简的搜索结果页面(简易网页采集器)
UA(User-Agent)检测:门户网站的服务器会检测对应请求的载体身份标识,如果检测到请求的载体身份标识为某一款浏览器说明请求是一个正常的请求;但是,如果检测到请求的载体身份标识不是基于某一款浏览器的,则标识该请求为不正常的请求(爬虫),则服务器端就很有可能会拒绝请求。
UA(User-Agent)伪装:将爬虫对应的请求载体身份识别伪装成浏览器。
import requests if __name__== "__main__": #UA伪装:对应User-Agent封装在字典里 headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36' } url = 'https://www.sogou.com/web' #处理URL携带参数:包装在字典中 kw = input(enter a word:')
param = {
'qurey' : kw
}
#对指定的URL发起的请求对应的URL是携带参数的,并且请求过程中处理了参数
response = requests.get(url= url,params= param ,headers= headers)
page_text = response.text
fileName = kw+'.html'
with open (fileName,'w',encoding='utf-8') as fp:
fp.write(page_text)
print(fileName,'保存成功')
破解百度翻译
~post请求(携带了参数)
~响应数据是一组JSON数据,其页面数据再其network下XHR(为AJAX)内容中寻找其完整属性值。其中,只要页面发生局部刷新,就是发生了AJAX请求,就需要到XHR中去寻找数据。
import json
import requests
if __name__ == "__main__":
#1.指定URL
post_url = 'https://fanyi.baidu.com/langdetect'
#2.进行UA伪装
header ={
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
}
#3.post请求参数处理(同get请求一致)
word = input('enter a word:')
data = {
'kw' : word
}
#4.请求发送
response = requests.post(url = post_url,data= data,headers=header)
#5.获取响应数据:json()方法返回的是obj(如果确认响应数据是json类型的,才可以使用json() )
dic_obj = response.json()
#持久化存储
fileName = word+'.json'
fp = open(fileName , 'w' ,encoding='utf-8')
json.dump(dic_obj , fp=fp,ensure_ascii=False,sort_keys=True)
print('over!')
爬取豆瓣电影分类排行榜
正则表达式批量添加引号(json数据)
(.?)😦.) 查找 ‘$1’:‘$2’,(替换)
import requests
import json
if __name__ == "__main__":
get_URL = 'https://movie.douban.com/j/chart/top_list'
#UA伪装:将对应的User-Agent封装到一个字典中
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
}
#param这个参数来自query String parameters控制检索数据的范围参数
param ={
' type':' 24',
' interval_id':' 100:90',
'action':'',
' start':' 5',
' limit':' 5',
}
response = requests.get(url=get_URL,params=param,headers=headers)
page_json=response.json()
fp = open('./humonsrank.json','w',encoding='utf-8')
json.dump(page_json , fp=fp,ensure_ascii=False,sort_keys=True)
print('over!')
爬取肯德基餐厅查询中指定地点的餐厅数据
网址:http://www.kfc.com.cn/kfccda/index.aspx
import requests
#在代码下方添加 if __name__ == '__main__':
#的主要原因是有时你需要你写的模块既可以直接的执行,
# 还可以被当做模块导入到其他模块中去.通过检查是不是主函数,
# 可以让你的代码只在它作为主程序运行时执行,
# 而当其他人调用你的模块中的函数的时候不必执行。
# 简单来说就是,方便我们代码复用,也可以测试模块。
if __name__ == '__main__':
post_url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
kw = input("输入:")
data = {
' cname':' ',
'pid':' ',
'keyword': kw,
'pageIndex':' 0',
'pageSize':' 10',
}
#UA伪装:将对应的User-Agent封装到一个字典中
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
}
response = requests.post(url=post_url,data=data,headers=headers)
page_text = response.text
print(page_text)
fileName = kw+'.html'
with open (fileName,'w',encoding='utf-8') as fp:
fp.write(page_text)
print(fileName,'保存成功')
爬取国家药品监督管理总局中基于中华共和国化妆品生产许可证相关数据
——动态加载数据
——首页中对应的企业信息数据是通过AJAX动态请求到的
——通过对详情页URL的观察发现:
--URL的域名都是一样的,只有携带的参数(ID)不一样
--ID值可以从首页对应的AJAX请求到的JSON串中获取
--域名和ID值拼接出一个完整的企业对应的详情页的URL
——详情页的数据也是通过AJAX请求得到的
--观察后发现:
--所有的post请求的URL都是一样的,只有参数ID值是不同。
--如果我们可以批量的获取多家企业的ID后,就可以将ID和URL形成一个完整的详情页对应详细数据的AJAX请求的URL
import json
import requests
if __name__ == "__main__":
URL = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsList'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
}
ID_list = [] #存储企业的ID
all_data_list =[] #存储所有的企业详情数据
#page控制获取页面数据数量
for page in range(1,6):
page = str(page)
data = {
' on':'true',
' page': page,
' pageSize':'15',
' productName':'',
' conditionType':'1',
' applyname':'',
' applysn':'',
}
#获取首页面AJAX信息中附带的ID信息
ID_Json = requests.post(url=URL,data=data,headers=headers).json()
#将获取的ID信息存放到ID_list中
for dic in ID_Json['list']:
ID_list.append(dic['ID'])
post_URL = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById'
#通过ID_list的ID来获取相应的详细数据
for id in ID_list:
data1 = {
'id' : id
}
detail_json= requests.post(url=post_URL,data=data1,headers=headers).json()
# print(detail_json,'----------------------ending-----------------------')
#添加到all_data_list中临时存储
all_data_list.append(detail_json)
#持久化存储
fp = open('./allData.json','w',encoding='utf-8')
json.dump(all_data_list,fp=fp,ensure_ascii=False)
print('over!')
四、数据解析
目的:实现聚焦爬虫。
聚焦爬虫的实现步骤:
指定URL、发起请求、获取响应数、数据解析、持久化存储。
分类:
-正则表达式
-bs4
-xpath(重点)
原理概述:
-解析的局部文本内容都会在标签之间或者标签对应的属性中进行存储
-①进行指定标签的定位
-②标签或者标签对应的属性中存储的数据值进行提取(解析)
1.正则表达式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pf9jeCFi-1654417233092)(C:\Users\wait\AppData\Roaming\Typora\typora-user-images\image-20220116115213180.png)]
爬取图片信息
爬取单独的图片
import requests
url = 'https://i0.hippopx.com/photos/242/966/413/dawn-sun-mountain-landscape-preview.jpg'
header ={
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
}
#content返回的是二进制形式的图片数据
#text(字符串) content(二进制) jSON() (响应数据,对象)
picture = requests.get(url=url,headers=header).content
with open('./sence.jpg','wb') as fp:
fp.write(picture)
对所有的图片进行聚焦爬虫
import requests
import re
import os
#<img itemprop="contentUrl" alt="ipad, 样机, 苹果, 业务, 计算机, 平板电脑, 工作场所"
# title="ipad, 样机, 苹果, 业务, 计算机, 平板电脑,
# 工作场所" src="https://i0.hippopx.com/photos/1014/122/418/ipad-mockup-apple-business-preview.jpg">
#创建一个文件夹保存所有的图片
if not os.path.exists('./photo'):
os.mkdir('./photo')
url = 'https://www.hippopx.com/zh/query?q=ipad'
header ={
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
}
#使用通用爬虫对URL对应的一整张页面进行爬取
page_text = requests.get(url=url,headers=header).text
#print(page_text)
#使用聚焦爬虫对页面中所有的图片信息进行截取
ex = '<img itemprop="contentUrl" alt=(.*?) title=(.*?) src=(.*?)>'
img_src_list= re.findall(ex,page_text,re.S)
ex2 = 'https?://(.*?)"'
img_src_list2=re.findall(ex2,str(img_src_list))
for src in img_src_list2:
#拼接出一个完整的图片URL
src = 'https://' +src
#请求到了图片的二进制数据
img_data = requests.get(url=src,headers=header).content
#生成图片名称
img_name = src.split('/')[-1]
#图片存储路径
imgpath = './photo' +img_name
with open (imgpath,'wb')as fp:
fp.write(img_data)
print(img_name,'下载成功!')
对所有图片分页爬取
import requests
import re
import os
#创建一个文件夹保存所有的图片
if not os.path.exists('./photo'):
os.mkdir('./photo')
header ={
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
}
url = 'https://www.hippopx.com/zh/query?q=ipad&page=%d'
for pageNum in range(1,10):
#对应平均页码的url
new_url = format(url%pageNum)
#使用通用爬虫对URL对应的一整张页面进行爬取
page_text = requests.get(url=url,headers=header).text
#print(page_text)
#使用聚焦爬虫对页面中所有的图片信息进行截取
ex = '<img itemprop="contentUrl" alt=(.*?) title=(.*?) src=(.*?)>'
img_src_list= re.findall(ex,page_text,re.S)
ex2 = 'https?://(.*?)"'
img_src_list2=re.findall(ex2,str(img_src_list))
for src in img_src_list2:
#拼接出一个完整的图片URL
src = 'https://' +src
#请求到了图片的二进制数据
img_data = requests.get(url=src,headers=header).content
#生成图片名称
img_name = src.split('/')[-1]
#图片存储路径
imgpath = './photo/' +img_name
with open (imgpath,'wb')as fp:
fp.write(img_data)
print(img_name,'下载成功!')
2.bs4进行数据解析
bs4数据解析原理:
-1.实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中
-2.通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取。
环境安装:
-pip install bs4
-pip install lxml
-如何实例化Beautifulsoup对象:
-from bs4 import beautifulsoup
-对象实例化:
-1.将本地的html文档中的数据加载到该对象中。
fp = open('./test.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')
-2.将互联网上获取的页面源码加载到该对象中。
page_text = response.text
soup = BeautifulSoup(page_text,'lxml')
-提供的用于数据解析的方法和属性:
– soup.tagName: 返回的是文档中第一次出现的tagName对应的标签
– soup.find():
--find(‘tagName’):等同于soup.tagName
– 属性定位:
--soup.find(‘div’,class_/id/attr=‘song’)
– soup.find_all(‘tagName’):返回符合要求的所有标签(列表)
– select:
--select(‘某种选择器(id, class,标签……选择器)’)返回的是一个列表。
– 层级选择器:
--soup.select(‘.tang > ul > li > a’): >表示的是一个层级
– soup.select(‘.tang > ul a’):空格标识多个层级
--获取标签之间的文本数据:
--soup.a.text/string/get_text()
--text/get_text():可以获取某一个标签中所有文本内容
--string:只可以获取该标签下面直系文本内容
– 获取标签中属性值:
– soup.a[‘tagName’]
爬取小说网站中小说的全部章节
import requests
from bs4 import BeautifulSoup
import lxml
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
}
url = 'https://www.shicimingju.com/book/sanguoyanyi.html'
#在首页中解析出章节的标题和详情页的url
#1.实例化BeautifulSoup对象,需要将页面源码数据加载到该对象中
page_enco = requests.get(url=url,headers=headers)
#解决编码错误问题
page_enco.encoding = 'utf-8'
page_text = page_enco.text
soup = BeautifulSoup(page_text,'lxml')
#解析章节标题和详情页url
title_text = soup.select('.book-mulu > ul > li')
#print(title_text)
fp=open('./sanguo.txt','w',encoding='UTF-8')
for li in title_text:
title = li.a.string
detail_url = 'https://www.shicimingju.com/'+li.a['href']
#对详情页发起请求,解析出章节内容
detail_name_enco = requests.get(url=detail_url , headers=headers)
detail_name_enco.encoding = 'utf-8'
detail_name_text =detail_name_enco.text
#解析出详情页中相关的章节内容
detail_soup = BeautifulSoup(detail_name_text,'lxml')
div_tag = detail_soup.find('div',class_='chapter_content')
#解析到了章节的内容
content = div_tag.text
fp.write(title+':'+content+'\n')
print(title,'爬取成功!')
3.xpath解析
最常用且最便捷高效的一种解析方式。通用性最强。
Xpath解析原理:
--1.实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中。
--2.调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获。
环境安装:
pip install lxml
如何实例化一个etree对象:
--1.将本地的html文档中的源码数据加载到etree对象中:
etree.parse(filePath)
– 2.可以将从互联网上获取的源码数据加载到该对象中
etree.HTML('page_text')
--xpath(‘xpath表达式’)
--. /表示从根节点开始定位。表示的是一个层级
--. //标识的是多个层级。可以表示从任意位置定位
tree = etree.parse('test.html')
r = tree.xpath('/html/body/div')
r = tree.xpath('/html//div')
r = tree.xpath('//div')
#三种结果一样
--. 属性定位://div[@class=‘song’] tag[@attrName=“attrValue”]
--.索引定位://div[@class=“song”]/p[3] 注:此时索引是从1开始的。
--.取文本:
--./test() 获取的标签中直系的文本内容
--.//test() 获取的标签中非直系的文本内容(所有的文本内容)
--.取属性:
--./@attrName ==>img/@src
#定位
r = tree.xpath('//div[@class="tagName"]')
#获取文本
r = tree.xpath('//div[@class="tagName"]//li[5]/a/test()')[0]
r = tree.xpath('//div[@class="tagName"]//test()')
#取属性
r = tree.xpath('div[@class="tagName"]/img/@src')
58同城二手房房源信息爬取
import requests
from lxml import etree
if __name__ =="__main__":
headers = {
'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36 Edg/97.0.1072.62'
}
url = 'https://hn.58.com/ershoufang/'
page_text = requests.get(url=url,headers=headers).text
#数据解析
tree = etree.HTML(page_text)
#确定存储对象位置
list =tree.xpath('//div[@class="property-content-title"]/h3/text()')
fp = open('./58.txt','w',encoding='utf-8')
#遍历写入文件
for li in list:
print(li+'\n')
fp.write(li+'\n')
图片解析爬取(解决中文乱码问题)
import requests
from lxml import etree
url = 'https://pic.netbian.com/'
headers = {
'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36 Edg/97.0.1072.62'
}
response = requests.get(url=url,headers=headers)
#手动设定响应数据的编码格式
#这种方式不行用下面的通用处理中文乱码的方式
#response.encoding = 'utf-8'
page_text = response.text
#解析数据
tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="slist"]/ul/li')
for li in li_list:
img_src='https://pic.netbian.com/'+li.xpath('./a/span/img/@src')[0]
#print(img_src)
img_name = li.xpath('./a/@title')[0]
#print(img_name)
img_data = requests.get(url=img_src,headers=headers).content
img_path = './photo/' + img_name +'.jpg'
#通用处理中文乱码的解决方案
img_name = img_name.encode('iso-8859-1').decode('gbk')
#持久化存储
with open(img_path,'wb')as fp :
fp.write(img_data)
print(img_name,'download successful!')
爬取网页中全国城市的名称
#分开取数据写法
import requests
from lxml import etree
if __name__ == '__main__':
url = 'https://www.aqistudy.cn/historydata/'
headers = {
'user-agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36 Edg/97.0.1072.62'
}
page_text = requests.get(url=url,headers=headers).text
tree = etree.HTML(page_text)
hot_li_city = tree.xpath('//div[@class="bottom"]/ul/li')
city_name = []
#解析到了热门城市的城市名称
for hot_city in hot_li_city:
city = hot_city.xpath('./a/text()')[0]
city_name.append(city)
#解析的