网页抓取数据(发送的最原始的请求就是GET请求(二))
优采云 发布时间: 2022-04-09 02:17网页抓取数据(发送的最原始的请求就是GET请求(二))
发送 GET 请求
当我们用浏览器打开豆瓣首页时,发送的最原创的请求其实是一个GET请求
import requests
res = requests.get('http://www.douban.com')
print(res)
print(type(res))
>>>
如您所见,我们得到的是一个 Response 对象
如果我们要获取网站返回的数据,可以使用text或者content属性来获取
text:以字符串的形式返回数据
内容:以二进制形式返回数据
print(type(res.text))
print(res.text)
>>>
.....
发送 POST 请求
对于 POST 请求,一般是提交表单
r = requests.post('http://www.xxxx.com', data={"key": "value"})
数据中有需要传递的表单信息,是字典类型的数据。
标题增强
对于一些网站,没有headers的请求会被拒绝,所以需要做一些header的增强。例如:UA、Cookie、主机等信息。
header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36",
"Cookie": "your cookie"}
res = requests.get('http://www.xxx.com', headers=header)
解析 HTML
既然我们已经获得了网页返回的数据,也就是HTML代码,我们就需要对HTML进行解析,提取出有效信息。
美丽汤
BeautifulSoup 是一个 Python 库,其主要功能是从网页中解析数据。
from bs4 import BeautifulSoup # 导入 BeautifulSoup 的方法
# 可以传入一段字符串,或者传入一个文件句柄。一般都会先用 requests 库获取网页内容,然后使用 soup 解析。
soup = BeautifulSoup(html_doc,'html.parser') # 这里一定要指定解析器,可以使用默认的 html,也可以使用 lxml。
print(soup.prettify()) # 按照标准的缩进格式输出获取的 soup 内容。
BeautifulSoup 的一些简单用法
print(soup.title) # 获取文档的 title
print(soup.title.name) # 获取 title 的 name 属性
print(soup.title.string) # 获取 title 的内容
print(soup.p) # 获取文档中第一个 p 节点
print(soup.p['class']) # 获取第一个 p 节点的 class 内容
print(soup.find_all('a')) # 获取文档中所有的 a 节点,返回一个 list
print(soup.find_all('span', attrs={'style': "color:#ff0000"})) # 获取文档中所有的 span 且 style 符合规则的节点,返回一个 list
具体用法和效果会在后面的实战中详细讲解。
XPath 定位
XPath 是 XML 的路径语言,用于通过元素和属性进行导航和定位。几种常用的表达方式
表达式含义 node 选择节点node的所有子节点/从根节点中选择//选择所有当前节点。当前节点..父节点@property select text() 当前路径下的文本内容
一些简单的例子
xpath('node') # 选取 node 节点的所有子节点
xpath('/div') # 从根节点上选取 div 元素
xpath('//div') # 选取所有 div 元素
xpath('./div') # 选取当前节点下的 div 元素
xpath('//@id') # 选取所有 id 属性的节点
当然XPath很强大,但是语法比较复杂,但是我们可以通过Chrome的开发者工具快速定位一个元素的xpath,如下图
生成的 xpath 是
//*[@id="anony-nav"]/div[1]/ul/li[1]/a
在实际使用过程中,到底是用BeautifulSoup还是XPath,完全看个人喜好,用哪个更熟练、更方便,就用哪个。
爬虫实战:爬虫豆瓣海报
从豆瓣映人页面,我们可以进入到对应的独映人映人图片页面。例如,以刘涛为例,她的英仁图片页地址是:
让我们分析一下这个页面
很多人学习python,不知道从哪里开始。
很多人学了python,掌握了基本的语法之后,都不知道去哪里找case入门了。
许多做过案例研究的人不知道如何学习更高级的知识。
所以针对这三类人,我会为大家提供一个很好的学习平台,免费的视频教程,电子书,还有课程的源码!
QQ群:721195303
目标网站页面分析
注意:网络上网站页面的构成会一直变化,所以这里需要学习分析,其他的网站等等。俗话说,授人以鱼不如授人以渔。
Chrome 开发者工具
Chrome开发者工具(按F12打开)是分析网页的优秀工具,一定要好好使用。
我们在任意一张图片上右击选择“Inspect”,可以看到“开发者工具”也打开了,图片的位置自动定位了。
可以清楚的看到每张图片都存放在li标签中,图片的地址存放在li标签中的img中。
知道了这些规则之后,我们就可以通过 BeautifulSoup 或者 XPath 来解析 HTML 页面,获取图片地址。
代码编写
我们只需要几行代码就可以完成图片url的提取
import requests
from bs4 import BeautifulSoup
url = 'https://movie.douban.com/celebrity/1011562/photos/'
res = requests.get(url).text
content = BeautifulSoup(res, "html.parser")
data = content.find_all('div', attrs={'class': 'cover'})
picture_list = []
for d in data:
plist = d.find('img')['src']
picture_list.append(plist)
print(picture_list)
>>>
['https://img1.doubanio.com/view/photo/m/public/p2564834267.jpg', 'https://img1.doubanio.com/view/photo/m/public/p860687617.jpg', 'https://img1.doubanio.com/view/photo/m/public/p2174001857.jpg', 'https://img1.doubanio.com/view/photo/m/public/p1563789129.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2363429946.jpg', 'https://img1.doubanio.com/view/photo/m/public/p2382591759.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2363269182.jpg', 'https://img1.doubanio.com/view/photo/m/public/p1959495269.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2356638830.jpg', 'https://img3.doubanio.com/view/photo/m/public/p1959495471.jpg', 'https://img3.doubanio.com/view/photo/m/public/p1834379290.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2325385303.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2361707270.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2325385321.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2196488184.jpg', 'https://img1.doubanio.com/view/photo/m/public/p2186019528.jpg', 'https://img1.doubanio.com/view/photo/m/public/p2363270277.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2325240501.jpg', 'https://img1.doubanio.com/view/photo/m/public/p2258657168.jpg', 'https://img1.doubanio.com/view/photo/m/public/p2319710627.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2319710591.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2311434791.jpg', 'https://img1.doubanio.com/view/photo/m/public/p2363270708.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2258657185.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2166193915.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2363265595.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2312085755.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2311434790.jpg', 'https://img3.doubanio.com/view/photo/m/public/p2276569205.jpg', 'https://img1.doubanio.com/view/photo/m/public/p2165332728.jpg']
如您所见,这是一个非常干净的列表,其中存储了海报地址。
但这里只是一页海报的数据。我们观察了页面,发现它有很多分页。如何处理分页。
寻呼
我们点击第二页,看看浏览器url的变化
发现浏览器url加了几个参数
再次点击第三页,继续观察url
通过观察我们可以看到,这里的参数中,只有start发生了变化,也就是变量,其余的参数都可以按常理处理。
同时也可以知道这个start参数应该起到类似于page的作用,start=30是第二页,start=60是第三页,以此类推,最后一页就是start=420。
所以我们处理分页的代码已经准备好了
首先将上面处理HTML页面的代码封装成一个函数
def get_poster_url(res):
content = BeautifulSoup(res, "html.parser")
data = content.find_all('div', attrs={'class': 'cover'})
picture_list = []
for d in data:
plist = d.find('img')['src']
picture_list.append(plist)
return picture_list
然后我们在另一个函数中处理分页并调用上面的函数
def fire():
page = 0
for i in range(0, 450, 30):
print("开始爬取第 %s 页" % page)
url = 'https://movie.douban.com/celebrity/1011562/photos/?type=C&start={}&sortby=like&size=a&subtype=a'.format(i)
res = requests.get(url).text
data = get_poster_url(res)
page += 1
至此,我们所有的海报数据都存储在data变量中,现在我们需要一个下载器来保存海报
def download_picture(pic_l):
if not os.path.exists(r'picture'):
os.mkdir(r'picture')
for i in pic_l:
pic = requests.get(i)
p_name = i.split('/')[7]
with open('picture\\' + p_name, 'wb') as f:
f.write(pic.content)
然后将下载器添加到fire函数中。此时为了防止豆瓣网的正常访问被请求过于频繁,将休眠时间设置为1秒。
def fire():
page = 0
for i in range(0, 450, 30):
print("开始爬取第 %s 页" % page)
url = 'https://movie.douban.com/celebrity/1011562/photos/?type=C&start={}&sortby=like&size=a&subtype=a'.format(i)
res = requests.get(url).text
data = get_poster_url(res)
download_picture(data)
page += 1
time.sleep(1)
fire函数在下面执行。程序运行完成后,会在当前目录下生成一个图片文件夹,里面保存着我们下载的所有海报。
核心代码说明
我们来看看完整的代码
import requests
from bs4 import BeautifulSoup
import time
import osdef fire():
page = 0
for i in range(0, 450, 30):
print("开始爬取第 %s 页" % page)
url = 'https://movie.douban.com/celebrity/1011562/photos/?type=C&start={}&sortby=like&size=a&subtype=a'.format(i)
res = requests.get(url).text
data = get_poster_url(res)
download_picture(data)
page += 1
time.sleep(1)def get_poster_url(res):
content = BeautifulSoup(res, "html.parser")
data = content.find_all('div', attrs={'class': 'cover'})
picture_list = []
for d in data:
plist = d.find('img')['src']
picture_list.append(plist)
return picture_listdef download_picture(pic_l):
if not os.path.exists(r'picture'):
os.mkdir(r'picture')
for i in pic_l:
pic = requests.get(i)
p_name = i.split('/')[7]
with open('picture\\' + p_name, 'wb') as f:
f.write(pic.content)if __name__ == '__main__':
fire()
消防功能
这是使用 range 函数处理分页的主要执行函数。
get_poster_url 函数
这是解析 HTML 的函数,使用 BeautifulSoup
下载图片功能
简易图片下载器
总结
本节讲解爬虫的基本流程以及需要用到的Python库和方法,并通过一个实例完成从分析网页到数据存储的整个流程。其实爬虫无非就是模拟请求,解析数据,保存数据。
当然,有时候,网站也会设置各种反爬机制,比如cookie验证、请求频率检查、非浏览器访问限制、JS混淆等等。这个时候,反反爬技术是需要的。比如抓取cookie放到headers中,使用代理IP访问,使用Selenium模拟浏览器等待模式。
这里推荐一下我自己建的Python学习群:721195303。群里的每个人都在学习Python。如果您想学习或正在学习Python,欢迎您的加入。大家都是软件开发党,不定期分享干货(仅限Python软件开发相关),包括我自己整理的2021最新Python进阶资料和零基础教学,欢迎进阶有兴趣的小伙伴加入Python!