爬虫学习笔记

0. 什么是爬虫?

通过编写程序,模拟浏览器上网,然后让其抓取数据的过程。

1. 常用请求头和响应头信息

1.1 常用请求头信息

  • User-Agent:请求载体的身份标识(如谷歌浏览器)。
  • Connection:请求完毕后是断开连接还是保持连接。

1.2 常用响应头信息

  • Content-Type:服务器响应回客户端的数据类型。

1.3 HTTPS协议

安全的HTTP协议。

加密方式:

  • 对称密钥加密
  • 非对称密钥加密
  • 证书密钥加密(HTTPS)

2. Requests库

2.1 作用

模拟浏览器发请求的过程。

2.2 入门案例

爬取搜狗首页。

import requests

# 1. 指定url
url = "http://www.sogou.com"

# 2. 发起请求
resp = requests.get(url=url)

# 3. 获取响应数据
print(type(resp.text))
''' <class 'str'> '''
print(resp.text)
''' (HTML文本) '''

# 4. 持久化存储
with open("./sogou.html", "w", encoding="utf-8") as fp:
    fp.write(resp.text)

2.3 UA伪装

爬取搜狗某个关键字的搜索结果。

import requests

# 1. 指定url
# url格式:https://www.sogou.com/web?query=%E4%BD%A0%E5%A6%88
url = "https://www.sogou.com/web"
params = {
    "query": "苏州大学",
}

# 2. UA伪装
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36 Edg/84.0.522.52",
}

# 3. 发起请求(带参数)
resp = requests.get(url=url, params=params, headers=headers)

# 4. 获取响应数据并持久化存储
with open("result.html", "w", encoding="utf-8") as fp:
    fp.write(resp.text)

2.4 带参数的URL

见上一节。

2.5 Ajax请求

爬取百度翻译的翻译结果。

2.5.1 在浏览器中抓取Ajax请求

在这里插入图片描述

2.5.2 分析请求和响应信息

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2.5.3 代码实现

import requests
import json

# 1. 指定url
url = "https://fanyi.baidu.com/sug"

# 2. POST请求参数处理
data = {
    "kw": "python",
}

# 3. UA伪装
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36 Edg/84.0.522.52",
}

# 4. 发起请求
resp = requests.post(url=url, data=data, headers=headers)

# 5. 获取响应数据(json)
json_data = resp.json()
print(json_data)
''' {'errno': 0, 'data': [{'k': 'python', 'v': 'n. 蟒; 蚺蛇;'}, {'k': 'pythons', 'v': 'n. 蟒; 蚺蛇;  python的复数;'}]} '''

# 6. 持久化存储
with open("result.json", "w", encoding="utf-8") as fp:
    json.dump(json_data, fp)

2.6 下载图片(二进制文件)

import requests

# 1. 指定url
url = "https://pic.qiushibaike.com/system/pictures/12343/123433317/medium/UURMN5VO96YT2MZX.jpg"

# 2. UA伪装
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36 Edg/84.0.522.52",
}

# 3. 发起请求
resp = requests.get(url=url, headers=headers)

# 4. 获取响应数据(二进制)
img_data = resp.content
print(type(img_data))
''' <class 'bytes'> '''

# 5. 持久化存储
with open("./img.jpg", "wb") as fp:
    fp.write(img_data)

2.7 综合应用

爬取豆瓣电影分类排行榜TOP100。

2.7.1 分析Ajax请求和响应信息

打开豆瓣电影分类排行榜,按F12开始抓取。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.7.2 代码实现

import requests

# 1. 指定url
url = "https://movie.douban.com/j/chart/top_list"
params = {
    "type": "24",
    "interval_id": "100:90",
    "action": "",
    "start": "0",    # 从库中第几部电影开始
    "limit": "100",  # 一次取出的数量
}

# 2. UA伪装
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36 Edg/84.0.522.52",
}

# 3. 发起请求
resp = requests.get(url=url, params=params, headers=headers)

# 4. 获取响应数据
json_data = resp.json()

# 5. 提取信息
for item in json_data:
    title = item.get("title")
    score = item.get("score")
    print(f"《{title}》\t评分:{score}")

在这里插入图片描述

3. 正则表达式

3.1 爬取图片

爬取糗事百科的图片。

3.1.1 分析HTML结构

在这里插入图片描述
可以看出,我们只需要处理class为“thumb”的div标签内的图片即可。

3.1.2 代码实现

import requests
import re
import os

# 1. 指定url
url = "https://www.qiushibaike.com/imgrank/"

# 2. UA伪装
headers = {
    # "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36 Edg/84.0.522.52",
}

# 3. 发起请求
resp = requests.get(url=url, headers=headers)

# 4. 获取响应数据
html = resp.text

# 5. 提取所有图片链接
pat = re.compile(r'<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>', re.S)
img_urls = pat.findall(html)
print(img_urls[:3])
''' ['//pic.qiushibaike.com/system/pictures/12329/123291166/medium/RUO963TBFGZH5VDK.jpg', '//pic.qiushibaike.com/system/pictures/12339/123394757/medium/4HAZDM2FIL6EOBY9.jpg', '//pic.qiushibaike.com/system/pictures/12342/123426805/medium/L197GOMSMVURGS8K.jpg'] '''

# 6. 下载所有图片
if not os.path.isdir("./img"):
    os.mkdir("./img")
for idx, img_url in enumerate(img_urls):
    assert img_url[:2] == "//"
    img_url = "https:" + img_url
    img_data = requests.get(url=img_url, headers=headers).content
    with open(f"./img/{idx}.jpg", "wb") as fp:
        fp.write(img_data)

4. BeautifulSoup

4.1 bs4数据解析的原理

  1. 实例化一个BeautifulSoup对象,将页面源码数据加载到该对象中
  2. 通过调用相应的方法,进行标签定位和数据提取

4.2 HTML演示代码

以下所有演示均是对该HTML代码进行的:

<html lang="zh-CN">
<head>
    <meta charset="UTF-8"/>
    <title>测试bs4</title>
</head>
<body>
<div>
    <p>百里守约</p>
</div>
<div class="song">
    <p>李清照</p>
    <p>王安石</p>
    <p>苏轼</p>
    <p>柳宗元</p>
    <a href="http://www.song.com/" title="赵匡胤" target="_self">
        <span>this is span</span>
        宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a>
    <a href="" class="du">总为浮云能蔽日,长安不见使人愁</a>
    <img src="http://www.baidu.com/meinv.jpg" alt=""/>
</div>
<div class="song">
    我也是一个song标签
</div>
<div class="tang">
    <ul>
        <li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>
        <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>
        <li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li>
        <li><a href="http://www.sina.com" class="du">杜甫</a></li>
        <li><a href="http://www.dudu.com" class="du">杜牧</a></li>
        <li><b>杜小月</b></li>
        <li><i>度蜜月</i></li>
        <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li>
    </ul>
</div>
</body>
</html>

4.3 获取标签

4.3.1 获取单个标签

from bs4 import BeautifulSoup

# 将本地HTML加载进BeautifulSoup对象
fp = open("in.html", "r", encoding="utf-8")
soup = BeautifulSoup(fp, "lxml")

# 1. 获取单个标签

# 1.1 获取文档中第一个<a>标签
tag_a = soup.a
print(type(tag_a))
''' <class 'bs4.element.Tag'> '''
print(tag_a)
'''
<a href="http://www.song.com/" target="_self" title="赵匡胤">
<span>this is span</span>
        宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a> '''

# 1.2 find()方法作用相同
tag_a = soup.find("a")
print(tag_a)


# 2. 属性定位

# 2.1 获取class为song的第一个标签
tag_div = soup.find("div", class_="song")
print(tag_div)


# 3. 获取一类标签

# 3.1 获取所有<a>标签
tag_as = soup.find_all("a")
print(type(tag_as))
''' <class 'bs4.element.ResultSet'> '''
print(len(tag_as))
''' 8 '''
print(type(tag_as[5]))
''' <class 'bs4.element.Tag'> '''


# 4. 选择器

# 4.1 选择class为song的所有标签
tag_song = soup.select(".song")
print(type(tag_song))
''' <class 'bs4.element.ResultSet'> '''
print(len(tag_song))
''' 2 '''
print(type(tag_song[0]))
''' <class 'bs4.element.Tag'> '''

# 4.2 直系层级选择(选择tang中li下所有儿子a标签)
tag_as = soup.select(".tang > ul > li > a")
print(tag_as)
''' [<a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a>, <a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a>, <a alt="qi" href="http://www.126.com">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a>, <a class="du" href="http://www.sina.com">杜甫</a>, <a class="du" href="http://www.dudu.com">杜牧</a>, <a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a>] '''

tag_as = soup.select(".tang > ul > a")
print(tag_as)
''' [] '''

# 4.3 非直系层级选择(选择ul下所有子孙a标签)
tag_as = soup.select(".tang > ul a")
print(tag_as)
''' [<a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a>, <a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a>, <a alt="qi" href="http://www.126.com">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a>, <a class="du" href="http://www.sina.com">杜甫</a>, <a class="du" href="http://www.dudu.com">杜牧</a>, <a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a>] '''

4.3.2 属性定位

见上一节。

4.3.3 获取一类标签

见上一节。

4.3.4 选择器(最常用)

见上一节。

4.4 获取标签内的文本数据

形如获取<p>abc</p>中间的“abc”。

from bs4 import BeautifulSoup

# 将本地HTML加载进BeautifulSoup对象
fp = open("in.html", "r", encoding="utf-8")
soup = BeautifulSoup(fp, "lxml")

# 1. tag.text/tag.get_text():获取标签内所有文本
tag_div = soup.select(".tang")[0]
print(tag_div.text)
'''
清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村
秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山
岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君
杜甫
杜牧
杜小月
度蜜月
凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘
'''

# 2. tag.string:获取标签的直系文本
print(tag_div.string)
''' None '''

tag_a = soup.select(".song > a")[0]
print(tag_a.string)
''' None '''

tag_p = soup.select(".song > p")[0]
print(tag_p.string)
''' 李清照 '''

4.5 获取标签的属性值

from bs4 import BeautifulSoup

# 将本地HTML加载进BeautifulSoup对象
fp = open("in.html", "r", encoding="utf-8")
soup = BeautifulSoup(fp, "lxml")

# 1. 获取所有a标签的href属性值
tag_as = soup.select("a")
for tag_a in tag_as:
    print(tag_a["href"])
'''
http://www.song.com/

http://www.baidu.com
http://www.163.com
http://www.126.com
http://www.sina.com
http://www.dudu.com
http://www.haha.com
'''

5. xpath

5.1 xpath解析原理

  1. 实例化一个etree的对象,并且需要将被解析的页面源码数据加载到该对象中。
  2. 调用etree对象中的xpath方法,结合着xpath表达式,实现标签定位和内容捕获。

5.2 HTML演示代码

以下所有演示均是对该HTML代码进行的:

<html lang="zh-CN">
<head>
    <meta charset="UTF-8"/>
    <title>测试bs4</title>
</head>
<body>
<div>
    <p>百里守约</p>
</div>
<div class="song">
    <p>李清照</p>
    <p>王安石</p>
    <p>苏轼</p>
    <p>柳宗元</p>
    <a href="http://www.song.com/" title="赵匡胤" target="_self">
        <span>this is span</span>
        宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a>
    <a href="" class="du">总为浮云能蔽日,长安不见使人愁</a>
    <img src="http://www.baidu.com/meinv.jpg" alt=""/>
</div>
<div class="song">
    我也是一个song标签
</div>
<div class="tang">
    <ul>
        <li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>
        <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>
        <li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li>
        <li><a href="http://www.sina.com" class="du">杜甫</a></li>
        <li><a href="http://www.dudu.com" class="du">杜牧</a></li>
        <li><b>杜小月</b></li>
        <li><i>度蜜月</i></li>
        <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li>
    </ul>
</div>
</body>
</html>

5.3 xpath语法

from lxml import etree

# 实例化etree对象
html = open("in.html", "r", encoding="utf-8").read()
tree = etree.HTML(html)

# 1. 从根结点开始定位“/”
div_tags = tree.xpath("/html/body/div")
print(type(div_tags))  # xpath()返回的永远是list
''' <class 'list'> '''
print(div_tags)
''' [<Element div at 0x22779bf9588>, <Element div at 0x22779bf9ac8>, <Element div at 0x22779bf9f08>, <Element div at 0x22779bfa0c8>] '''


# 2. 跨越层级“//”
# 2.1 /html下所有子孙div
div_tags = tree.xpath("/html//div")
print(div_tags)
''' [<Element div at 0x202e25d8e48>, <Element div at 0x202e25d8b88>, <Element div at 0x202e25d8ec8>, <Element div at 0x202e25d8f08>] '''

# 2.2 整个文档下所有子孙div
div_tags = tree.xpath("//div")
print(div_tags)
''' [<Element div at 0x202e25d8e48>, <Element div at 0x202e25d8b88>, <Element div at 0x202e25d8ec8>, <Element div at 0x202e25d8f08>] '''


# 3. 属性定位 & 索引定位
# 3.1 所有class为song的div标签
div_tags = tree.xpath('//div[@class="song"]')
print(div_tags)
''' [<Element div at 0x2699476a308>, <Element div at 0x2699476a388>] '''

# 3.2 满足条件的第3个p标签(索引从1开始)
div_tags = tree.xpath('//div[@class="song"]/p[3]')
print(div_tags)
''' [<Element p at 0x2699476adc8>] '''


# 4. 获取标签的文本 & 属性
# 4.1 获取a标签的文本(直系)
a_text = tree.xpath("//div[@class='tang']//li[5]/a/text()")
print(a_text)
''' ['杜牧'] '''

# 4.2 获取标签下所有子孙文本
li_text = tree.xpath("//li[7]/text()")
print(li_text)
''' [] '''

li_text = tree.xpath("//li[7]//text()")
print(li_text)
''' ['度蜜月'] '''

li_text = tree.xpath("//div[@class='tang']//text()")
print(li_text)
''' ['n    ', '\n        ', '清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村', '\n        ', '秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山', '\n        ', '岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君', '\n        ', '杜甫', '\n        ', '杜牧', '\n        ', '杜小月', '\n        ', '度蜜月', '\n        ', '凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘', '\n    ', '\n'] '''

# 4.3 获取标签的属性值
url = tree.xpath("//div[@class='song']/img/@src")
print(url)
''' ['http://www.baidu.com/meinv.jpg'] '''

注:对于每个获取到的Element对象,可以继续调用xpath()方法!但是要以“./”开始,表示相对路径。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值