目录
视频资料见B站
1.爬虫简介(课程最后补充异步编程课程)_哔哩哔哩_bilibili
爬虫基本知识
什么是爬虫:
通过编写程序,模拟浏览器上网,然后让其去互联网上抓取数据的过程。
爬虫在使用场景中的分类 :
1、通用爬虫:抓取系统(每个浏览器都有抓取系统)重要组成部分。抓取的是一整张页面数据。
2、聚焦爬虫: 是建立在通用爬虫的基础之上。抓取的是页面中特定的局部内容。
3、增量式爬虫: 检测网站中数据更新的情况。只会抓取网站中最新更新出来的数据。
反爬机制:
门户网站可以通过制定相应的策略或者技术手段,防止爬虫程序进行网站数据的爬取。
反反爬策略 :
爬虫程序可以通过制定相关的策略或者技术手段,破解门户网站中具备的反爬机制,从而可以获取门户网站数据 robots.txt协议(君子协议)。规定了网站中哪些数据可以被爬虫爬取哪些数据不可以被爬取。 比如淘宝国际版的:https://world.taobao.com/robots.txt
其他:
http协议 :就是服务器和客户端进行数据交互的一种形式。
常用请求头信息 User-Agent:请求载体的身份标识 ;Connection:请求完毕后,是断开连接还是保特连接
常用响应头信息 Content-Type:服务器响应回客户端的数据类型
https协议: 一安全的超文本传输协议
加密方式 :对称秘钥加密 ;非对称秘钥加密; 证书秘钥加密 (https采用)
requests模块基础
基于网络请求的两个模块:urllib模块(老,繁琐),requests模块(新,重点学这个)
requests模块:python中原生的一款基于网络请求的模块,功能非常强大,简单便捷,效率高。
作用:模拟浏览器发请求。
如何使用:(requests模块的编码流程)
1、指定url
2、UA伪装
3、请求参数的处理
4、发起请求
5、获取响应数据
6、持久化存储
实战编码:
需求:爬取搜狗首页的页面数据
# 需求:爬取搜狗首页的页面数据
import requests
url='https://www.sogou.com/'
response=requests.get(url)
page=response.text
with open('./sogou.html','w',encoding='utf-8') as fp:
fp.write(page)
需求:爬取搜狗指定词条对应的搜索结果页面(简易网页采集器)
# 需求:爬取搜狗指定词条对应的搜索结果页面(简易网页采集器)
import requests
#UA伪装:让爬虫对应的请求载体身份标识伪装成某一款浏览器,User-Agent可以在任一网页抓包得到:右键-检查-网络-刷新页面-找User-Agent即可
headers={
'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Mobile Safari/537.36 Edg/103.0.1264.49'
}
url ='https://www.sogou.com/web' # 百度更改为 'https://www.baidu.com/s'
#处理url携带的参数:封装到字典中
kw=input('enter a word:')
param = {
'query':kw # 百度更改为 'wd':kw
}
#对指定的url发起的请求对应的url是携带参数的,并且请求过程中处理了参数
response=requests.get(url=url,params=param,headers=headers)
page=response.text
fileName=kw+'.html'
with open(fileName,'w',encoding='utf-8')as fp:
fp.write(page)
print(fileName,'保存成功!!!')
UA:User-Agent(请求载体的身份标识】
UA检测(一种反扒机制):门户网站的服务器会检测对应请求的载体身份标识,如果检测到请求的载体身份标识为某一款浏览器, 则说明该通求是一个正常的请求,但是,如果检测到请求的载体身份标识不是基于某一款浏览器, 则表示该请求为不正常的请求(爬虫),则服务器端很有可能拒绝该次请求 。
UA伪装(一种反反扒策略):让爬虫对应的请求载体身份标识伪装成某一款浏览器
需求:破解百度翻译
#需求:破解百度翻译 (注意:最后fp.close()不要忘了,否则生成的文件是空的)
import requests
import json
#1.指定url
post_url='https://fanyi.baidu.com/sug'
#2.进行UA伪装
headers={
'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Mobile Safari/537.36 Edg/103.0.1264.49'
}
#3.post请求参数处理(同get请求一致)
word=input('enter a word:')
data = {
'kw':word
}
#4.请求发送
response=requests.post(url=post_url,data=data,headers=headers)
#5.获取响应数据:json()方法返回的是obj(如果确认响应数据是json类型的,才可以使用)
dic_obj=response.json()
#持久化存储
fileName=word+'.json'
# with open(fileName,'w',encoding='utf-8')as fp:
# fp.write(page) #之所以不用这种方法保存文件是因为write()里面的参数是str类型,而此处的dic_obj是dict类型
fp=open(fileName,'w',encoding='utf-8')
json.dump(dic_obj,fp=fp,ensure_ascii=False)
fp.close() # 如果没有这一步,文件就是空文件
print('over!!')
需求:爬取豆瓣电影分类排行榜https://movie.douban.com/中的电影详情数据
#需求:爬取豆瓣电影分类排行榜https://movie.douban.com/中的电影详情数据
#https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=20 (本次用这个)
# 此数据来自于ajax请求,因为页面信息变化时,网址并不变。若想拿到该网址,需要使用F12抓包
#url都是截取的“?”前的,“?”后的需要写成字典形式。
import requests
import json
url='https://movie.douban.com/j/search_subjects'
param={
'type': 'movie',
'tag': '热门',
'sort': 'recommend',
'page_limit': '100',
'page_start': '0'
}
headers={
'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Mobile Safari/537.36 Edg/103.0.1264.49'
}
response=requests.get(url=url,params=param,headers=headers)
list_data=response.json()
fp=open('./movie.json','w',encoding='utf-8')
json.dump(list_data,fp=fp,ensure_ascii=False)
fp.close()
print("over!!")
需求:爬取肯德餐厅查询http://www.kfc.com.cn/kfccda/storelist/index.aspx中指定地点的餐厅
# 需求:爬取肯德餐厅查询http://www.kfc.com.cn/kfccda/storelist/index.aspx中指定地点的餐厅
import requests
import json
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
keyword = input('请输入城市:')
data = {
'cname':'',
'pid':'',
'keyword':keyword,
'pageIndex':'1',
'pageSize':'10'
}
headers={
'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Mobile Safari/537.36 Edg/103.0.1264.49'
}
response = requests.post(url=url,data=data,headers=headers)
page_text = response.json()
filename = keyword+'.json'
fp = open(filename,'w',encoding='utf-8')
data = json.dump(page_text,fp=fp,ensure_ascii=False)
fp.close()
print('成功')
-
数据解析
-
聚焦爬虫:爬取页面中指定的页面内容。
-
编码流程:指定url 发起请求 获取响应数据 数据解析 持久化存储
-
数据解析分类:1、正则表达式;2、bs4(beautifulsoup);3、xpath(重点学习)
数据解析原理概述:
解析的局部的文本内容都会在标签之间或者标签对应的属性中进行存储
1.进行指定标签的定位
2.标签或者标签对应的属性中存储的数据值进行提取(解析)-
1、正则解析:
-
对于下面的网页:
<div class="thumb"><a href="/article/121721100" target="_blank">
<imgsrc="//pic.qiushibaike.com/system/pictures/12172/121721100/medium/DNXDX9TZ8SDU6OK2.jpg" alt="指引我有前进的方向">
</a></div> -
构造一个正则表达式,最后匹配的结果为图片路径:
ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>' - 2、bs4进行数据解析
- 数据解析的原理: 1.标签定位 2.提取标签、标签属性中存储的数据值
- 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 = BeatifulSoup(page_text,'lxml')
提供的用于数据解析的方法和属性:
soup.tagName:返回的是文档中第一次出现的tagName对应的标签
soup.find():
find('tagName'):等同于soup.div
属性定位:
soup.find('div',class_/id/attr='song')
soup.find_all('tagName'):返回符合要求的所有标签(列表)
select: select('某种选择器(id,class,标签...选择器)'),返回的是一个列表。
层级选择器:
soup.select('.tang > ul > li > a'):>表示的是一个层级
oup.select('.tang > ul a'):空格表示的多个层级
获取标签之间的文本数据:
soup.a.text/string/get_text()
text/get_text():可以获取某一个标签中所有的文本内容
string:只可以获取该标签下面直系的文本内容
获取标签中属性值:
soup.a['href']3、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表达式:
-
/:表示的是从根节点开始定位。表示的是一个层级。
//:表示的是多个层级。可以表示从任意位置开始定位。
属性定位://div[@class='song'] tag[@attrName="attrValue"]
索引定位://div[@class="song"]/p[3] 索引是从1开始的。
取文本:
/text() 获取的是标签中直系的文本内容
//text() 标签中非直系的文本内容(所有的文本内容)
取属性:
/@attrName ==>img/src -
需求实战:
-
需求:使用正则解析 爬取某高校信工院所有副教授照片
import requests
import re
import os
if __name__ == "__main__":
#创建一个文件夹,保存所有的图片
if not os.path.exists('./fujiaoshouLibs'):
os.mkdir('./fujiaoshouLibs')
url = 'https://xg.xcu.edu.cn/xygk/xyjs/fjs.htm'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
#使用通用爬虫对url对应的一整张页面进行爬取
page_text = requests.get(url=url,headers=headers).text
#使用聚焦爬虫将页面中所有的教授照片进行解析/提取
exurl = '<img width="125" height="182" src="(.*?)"'
img_src_list = re.findall(exurl,page_text,re.S)
for src in img_src_list:
#拼接出一个完整的图片url
src = 'https://xg.xcu.edu.cn'+src
#请求到了图片的二进制数据
img_data = requests.get(url=src,headers=headers).content
#生成图片名称
img_name = src.split('/')[-1]
#图片存储的路径
imgPath = './fujiaoshouLibs/'+img_name
with open(imgPath,'wb') as fp:
fp.write(img_data)
print(img_name,'下载成功!!!')
需求:使用bs4 爬取三国演义小说所有的章节标题和章节内容(方法一)
# -*- coding:utf-8 -*-
import requests
from bs4 import BeautifulSoup
#https://so.gushiwen.cn/guwen/book_46653FD803893E4F7F702BCF1F7CCE17.aspx
if __name__ == "__main__":
#对首页的页面数据进行爬取
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
url = 'https://so.gushiwen.cn/guwen/book_46653FD803893E4F7F702BCF1F7CCE17.aspx'
page_text = requests.get(url=url,headers=headers).text
#在首页中解析出章节的标题和详情页的url
#1.实例化BeautifulSoup对象,需要将页面源码数据加载到该对象中
soup = BeautifulSoup(page_text,'lxml')
#解析章节标题和详情页的url
a_list = soup.select('.bookcont > ul a')
# print(len(a_list))
fp = open('./sanguo.txt','w',encoding='utf-8')
for i in range(len(a_list)):
title = a_list[i].string
detail_url = a_list[i]['href']
# print(title)
#对详情页发起请求,解析出章节内容
detail_page_text = requests.get(url=detail_url,headers=headers).text
#解析出详情页中相关的章节内容
detail_soup = BeautifulSoup(detail_page_text,'lxml')
div_tag = detail_soup.find('div',class_='contson')
#解析到了章节的内容
content = div_tag.text
fp.write(title+':'+content+'\n')
print(title,'爬取成功!!!')
需求:使用bs4 爬取三国演义小说所有的章节标题和章节内容(方法二)
# -*- coding:utf-8 -*-
import requests
from bs4 import BeautifulSoup
# https://so.gushiwen.cn/guwen/book_46653FD803893E4F7F702BCF1F7CCE17.aspx
if __name__ == "__main__":
#对首页的页面数据进行爬取
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
url = 'https://so.gushiwen.cn/guwen/book_46653FD803893E4F7F702BCF1F7CCE17.aspx'
page_text = requests.get(url=url,headers=headers).text
#在首页中解析出章节的标题和详情页的url
#1.实例化BeautifulSoup对象,需要将页面源码数据加载到该对象中
soup = BeautifulSoup(page_text,'lxml')
#解析章节标题和详情页的url
span_list = soup.select('.bookcont > ul > span')
fp = open('./sanguo1.txt','w',encoding='utf-8')
for s in span_list:
title = s.a.string
detail_url = s.a['href']
# print(detail_url)
#对详情页发起请求,解析出章节内容
detail_page_text = requests.get(url=detail_url,headers=headers).text
#解析出详情页中相关的章节内容
detail_soup = BeautifulSoup(detail_page_text,'lxml')
div_tag = detail_soup.find('div',class_='contson')
#解析到了章节的内容
content = div_tag.text
fp.write(title+':'+content+'\n')
print(title,'爬取成功!!!')
需求:使用xpath爬取赶集网所有计算机工作岗位+薪资+地点 (之前查58的网站,但有反扒机制,每次爬到的东西都是空列表,故放弃。之后发现换个不同的User-Agent就可以了)
# -*- coding:utf-8 -*-
import requests
from lxml import etree
headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
}
#爬取到页面源码数据
url = 'https://sz.ganji.com/chengxuyuan/'
page_text = requests.get(url=url,headers=headers).text
#数据解析
tree = etree.HTML(page_text)
#存储的就是li标签对象
tr_list = tree.xpath('//div[@class="ibox"]')
# print(tr_list)
fp = open('赶集.txt','w',encoding='utf-8')
for tr in tr_list:
#局部解析
title = tr.xpath('.//li[@class="ibox-title"]/text()')[0]
salary =tr.xpath('.//li[@class="ibox-salary"]/text()')[0]
address =tr.xpath('.//li[@class="ibox-address"]/text()')[0]
# print(title)
fp.write(title+salary+' '+address+'\n')
fp.close()
需求:使用xpath解析下载图片数据 http://pic.netbian.com/4kmeinv/
# -*- coding:utf-8 -*-
import requests
from lxml import etree
import os
if __name__ == "__main__":
url = 'http://pic.netbian.com/4kfengjing/'
headers = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
}
response = requests.get(url=url,headers=headers)
#手动设定响应数据的编码格式
# response.encoding = 'utf-8'
page_text = response.text
#数据解析:src的属性值 alt属性
tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="slist"]/ul/li')
#创建一个文件夹
if not os.path.exists('./picLibs'):
os.mkdir('./picLibs')
for li in li_list:
img_src = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0]
img_name = li.xpath('./a/img/@alt')[0]+'.jpg'
#通用处理中文乱码的解决方案
img_name = img_name.encode('iso-8859-1').decode('gbk')
# print(img_name,img_src)
#请求图片进行持久化存储
img_data = requests.get(url=img_src,headers=headers).content
img_path = 'picLibs/'+img_name
with open(img_path,'wb') as fp:
fp.write(img_data)
print(img_name,'下载成功!!!')