爬虫
- 爬虫
- requests
- scrapy
- 数据分析+机器学习
- numpy,pandas,matplotlib
- 学习方法:
- Anaconda是一个集成环境(基于机器学习和数据分析的开发环境)
- 基于浏览器的一种可视化开发工具:jupyter notebook
- 可以在指定目录的终端中录入jupyter notebook指令,然后启动服务。
- cell是分为不同模式的:
- Code:编写python代码
- markDown:编写笔记
- 快捷键:
- 添加cell:a,b
- 删除cell:x
- 执行:shift+enter
- tab:
- 切换cell的模式:
- m
- y
- 打开帮助文档:shift+tab
什么是爬虫?
- 就是通过编写程序模拟浏览器上网,然后让其去互联网上爬取数据的过程
爬虫的分类:
- 通用爬虫:
- 抓取互联网中的一整张页面数据
- 聚焦爬虫:
- 抓取页面中的局部数据
- 增量式爬虫:
- 用来监测网站数据更新的情况,以便爬取到网站最新更新出来的数据
- 通用爬虫:
反爬机制
反反爬策略
爬虫合法吗?
爬取数据的行为风险的体现:
- 爬虫干扰了被访问网站的正常运营;
- 爬虫抓取了受到法律保护的特定类型的数据或信息。
规避风险:
严格遵守网站设置的robots协议;
在规避反爬虫措施的同时,需要优化自己的代码,避免干扰被访问网站的正常运行;
在使用、传播抓取到的信息时,应审查所抓取的内容,如发现属于用户的个人信息、隐私或者他人的商业秘密的,应及时停止并删除。
robots协议:文本协议
- 特性:防君子不防小人的文本协议
- 什么是requests模块?
- Python中封装好的一个基于网络请求的模块。
- requests模块的作用?
- 用来模拟浏览器发请求
- requests模块的环境安装:
- pip install requests
- requests模块的编码流程:
- 1.指定url
- 2.发起请求
- 3.获取响应数据
- 4.持久化存储
#爬取搜狗首页的页面源码数据 import requests #1.指定url url = 'https://www.sogou.com/' #2.请求发送get:get返回值是一个响应对象 response = requests.get(url=url) #3.获取响应数据 page_text = response.text #返回的是字符串形式的响应数据 #4.持久化存储 with open('sogou.html','w',encoding='utf-8') as fp: fp.write(page_text)
实现一个简易的网页采集器 需要让url携带的参数动态化 url = 'https://www.sogou.com/web' 实现参数动态化 wd = input('enter a key:') params = { 'query':wd } 在请求中需要将请求参数对应的字典作用到params这个get方法的参数中 response = requests.get(url=url,params=params)page_text = response.text
fileName = wd+'.html'
with open(fileName,'w',encoding='utf-8') as fp:
fp.write(page_text)
上述代码执行后发现:
- 1.出现了乱码
- 2.数据量级不对
解决乱码url = 'https://www.sogou.com/web'
实现参数动态化
wd = input('enter a key:')
params = {
'query':wd
}
在请求中需要将请求参数对应的字典作用到params这个get方法的参数中
response = requests.get(url=url,params=params)
response.encoding = 'utf-8' #修改响应数据的编码格式
page_text = response.text
fileName = wd+'.html'
with open(fileName,'w',encoding='utf-8') as fp:
fp.write(page_text)
- UA检测:门户网站通过检测请求载体的身份标识判定改请求是否为爬虫发起的请求
- UA伪装:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
解决UA检测 url = 'https://www.sogou.com/web' #实现参数动态化 wd = input('enter a key:') params = { 'query':wd } headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36' } 在请求中需要将请求参数对应的字典作用到params这个get方法的参数中 response = requests.get(url=url,params=params,headers=headers) response.encoding = 'utf-8' #修改响应数据的编码格式 page_text = response.text fileName = wd+'.html' with open(fileName,'w',encoding='utf-8') as fp: fp.write(page_text)
#爬取的是豆瓣电影中电影的详情数据https://movie.douban.com/typerank?type_name=%E7%88%B1%E6%83%85&type=13&interval_id=100:90&action=
#分析:当滚动条被滑动到页面底部的时候,当前页面发生了局部刷新(ajax的请求)
动态加载的页面数据
- 是通过另一个单独的请求请求到的数据
url = 'https://movie.douban.com/j/chart/top_list' start = input('您想从第几部电影开始获取:') limit = input('您想获取多少电影数据:') dic = { 'type': '13', 'interval_id': '100:90', 'action': '', 'start': start, 'limit': limit, } response = requests.get(url=url,params=dic,headers=headers) page_text = response.json() #json()返回的是序列化好的实例对象 for dic in page_text: print(dic['title']+':'+dic['score'])
肯德基餐厅查询http://www.kfc.com.cn/kfccda/storelist/index.aspx url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword' for page in range(1,5): data = { 'cname': '', 'pid': '', 'keyword': '西安', 'pageIndex': str(page), 'pageSize': '10', } response = requests.post(url=url,headers=headers,data=data) print(response.json())
- 需求
- 爬取药监总局中相关企业的详情信息http://125.35.6.84:81/xk/
- 需求分析
- 如何检测页面中是否存在动态加载的数据?
- 基于抓包工具实现
- 先捕获网站请求后所有的数据包
- 在数据包中定位到地址栏所对应请求的数据包,在response选项卡对应的数据中进行局部搜索(页面中的某一组内容)
- 可以搜索到:爬取的数据不是动态加载的
- 没有搜索到:爬取的数据是动态加载的
- 如何定位动态加载的数据在哪个数据包中呢?
- 进行全局搜索
- 基于抓包工具实现
- 数据解析的作用:
- 可以帮助我们实现聚焦爬虫
- 数据解析的实现方式:
- 正则
- bs4
- xpath
- pyquery
- 数据解析的通用原理
- 问题1:聚焦爬虫爬取的数据是存储在哪里的?
- 都被存储在了相关的标签之中and相关标签的属性中
- 1.定位标签
- 2.取文本或者取属性
数据解析
import requests
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36'
}
#如何爬取图片 url = 'https://pic.qiushibaike.com/system/pictures/12223/122231866/medium/IZ3H2HQN8W52V135.jpg' img_data = requests.get(url,headers=headers).content #byte类型数据 with open('./img.jpg','wb') as fp: fp.write(img_data)
#弊端:不能使用UA伪装 from urllib import request url = 'https://pic.qiushibaike.com/system/pictures/12223/122231866/medium/IZ3H2HQN8W52V135.jpg' request.urlretrieve(url,filename='./qiutu.jpg')
import re import os糗图爬取1-3页所有的图片
1.使用通用爬虫将前3页对应的页面源码数据进行爬取
通用的url模板(不可变)
dirName = './imgLibs'
if not os.path.exists(dirName):
os.mkdir(dirName)
url = 'https://www.qiushibaike.com/pic/page/%d/'
for page in range(1,4):
new_url = format(url%page)
page_text = requests.get(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:
src = 'https:'+src
img_name = src.split('/')[-1]
img_path = dirName+'/'+img_name #./imgLibs/xxxx.jpg
request.urlretrieve(src,filename=img_path)
print(img_name,'下载成功!!!')
bs4解析
- bs4解析的原理:
- 实例化一个BeautifulSoup的对象,需要将即将被解析的页面源码数据加载到该对象中
- 调用BeautifulSoup对象中的相关方法和属性进行标签定位和数据提取
- 环境的安装:
- pip install bs4
- pip install lxml
- BeautifulSoup的实例化:
- BeautifulSoup(fp,'lxml'):将本地存储的一个html文档中的数据加载到实例化好的BeautifulSoup对象中
- BeautifulSoup(page_text,'lxml'):将从互联网上获取的页面源码数据加载到实例化好的BeautifulSoup对象中
- bs4解析的原理:
- 定位标签的操作:
- soup.tagName:定位到第一个出现的tagName标签
- 属性定位:soup.find('tagName',attrName='value')
- 属性定位:soup.find_all('tagName',attrName='value'),返回值为列表
- 选择器定位:soup.select('选择器')
- 层级选择器:>表示一个层级 空格表示多个层级
- 取文本
- .string:获取直系的文本内容
- .text:获取所有的文本内容
- 取属性
- tagName['attrName']
from bs4 import BeautifulSoup fp = open('./test.html','r',encoding='utf-8') soup = BeautifulSoup(fp,'lxml') soup.div soup.find('div',class_='song') soup.find('a',id="feng") soup.find_all('div',class_="song") soup.select('#feng') soup.select('.tang > ul > li') soup.select('.tang li') # a_tag = soup.select('#feng')[0] a_tag.text div = soup.div div.string div = soup.find('div',class_="song") div.string a_tag = soup.select('#feng')[0] a_tag['href']
#爬取三国整篇内容(章节名称+章节内容)http://www.shicimingju.com/book/sanguoyanyi.html fp = open('sanguo.txt','w',encoding='utf-8') main_url = 'http://www.shicimingju.com/book/sanguoyanyi.html' page_text = requests.get(main_url,headers=headers).text #解析出章节名称和章节详情页的url soup = BeautifulSoup(page_text,'lxml') a_list = soup.select('.book-mulu > ul > li > a') #返回的列表中存储的是一个个a标签 for a in a_list: title = a.string detail_url = 'http://www.shicimingju.com'+a['href'] detail_page_text = requests.get(detail_url,headers=headers).text #解析详情页中的章节内容 soup = BeautifulSoup(detail_page_text,'lxml') content = soup.find('div',class_='chapter_content').text fp.write(title+':'+content+'\n') print(title,'下载成功!') fp.close()
xpath解析
- xpath解析的实现原理
- 1.实例化一个etree的对象,然后将即将被解析的页面源码加载到改对象中
- 2.使用etree对象中的xpath方法结合着不同形式的xpath表达式实现标签定位和数据提取
- 环境安装:
- pip install lxml
- etree对象的实例化:
- etree.parse('test.html')
- etree.HTML(page_text)
- xpath表达式:xpath方法的返回值一定是一个列表
- 最左侧的/表示:xpath表达式一定要从根标签逐层进行标签查找和定位
- 最左侧的//表示:xpath表达式可以从任意位置定位标签
- 非最左侧的/:表示一个层级
- 非最左侧的//:表示夸多个层级
- 属性定位://tagName[@attrName="value"]
- 索引定位://tagName[index] 索引是从1开始
- 取文本:
- /text():直系文本内容
- //text():所有的文本内容
- 取属性:
- /@attrName
from lxml import etree tree = etree.parse('./test.html') tree.xpath('/html/head/title') tree.xpath('//title') tree.xpath('/html/body//p') tree.xpath('//p') tree.xpath('//div[@class="song"]') tree.xpath('//li[7]') tree.xpath('//a[@id="feng"]/text()')[0] tree.xpath('//div[@class="song"]//text()') tree.xpath('//a[@id="feng"]/@href')爬取糗百中的段子内容和作者名称
url = 'https://www.qiushibaike.com/text/'
page_text = requests.get(url,headers=headers).text解析内容
tree = etree.HTML(page_text)
div_list = tree.xpath('//div[@id="content-left"]/div')
for div in div_list:
author = div.xpath('./div[1]/a[2]/h2/text()')[0]#实现局部解析
content = div.xpath('./a[1]/div/span//text()')
content = ''.join(content)<span style="color: rgb(0, 0, 255);">print</span>(author,content)
http://pic.netbian.com/4kmeinv/中文乱码的处理
dirName = './meinvLibs'
if not os.path.exists(dirName):
os.mkdir(dirName)
url = 'http://pic.netbian.com/4kmeinv/index_%d.html'
for page in range(1,11):
if page == 1:
new_url = 'http://pic.netbian.com/4kmeinv/'
else:
new_url = format(url%page)
page_text = requests.get(new_url,headers=headers).text
tree = etree.HTML(page_text)
a_list = tree.xpath('//div[@class="slist"]/ul/li/a')
for a in a_list:
img_src = 'http://pic.netbian.com'+a.xpath('./img/@src')[0]
img_name = a.xpath('./b/text()')[0]
img_name = img_name.encode('iso-8859-1').decode('gbk')
img_data = requests.get(img_src,headers=headers).content
imgPath = dirName+'/'+img_name+'.jpg'
with open(imgPath,'wb') as fp:
fp.write(img_data)
print(img_name,'下载成功!!!')// https://www.aqistudy.cn/historydata/所有城市名称
page_text = requests.get('https://www.aqistudy.cn/historydata/',headers=headers).text
tree = etree.HTML(page_text)
hot_cities = tree.xpath('//div[@class="bottom"]/ul/li/a/text()')
all_cities = tree.xpath('//div[@class="bottom"]/ul/div[2]/li/a/text()')
cities = tree.xpath('//div[@class="bottom"]/ul/div[2]/li/a/text() | //div[@class="bottom"]/ul/li/a/text()') #提高xpath的通用性
cities
http://sc.chinaz.com/jianli/free.html 免费的简历模板进行爬取和保存
--------------------- end ---------------------------