python爬虫入门实现

本文详细介绍了Python网络爬虫的基础知识,包括requests库的使用,如GET、POST等HTTP方法,以及如何处理异常。还提到了网页解析库BeautifulSoup的使用,如标签遍历和内容提取。同时,讲解了网络爬虫的道德规范,如遵循Robots协议,并给出了实际的爬虫代码示例,涉及京东、亚马逊等网站的页面抓取。
摘要由CSDN通过智能技术生成

首先,我们要理解什么是爬虫。
百度百科上爬虫的定义:

网络爬虫(web crawler)也叫网页蜘蛛,网络机器人,是一种用来自动浏览万维网的程序或者脚本。爬虫可以验证超链接和HTML代码,用于网络抓取(Web scraping)。网络搜索引擎等站点通过爬虫软件更新自身的网站内容(Web content)或其对其他网站的索引。 爬虫访问网站的过程会消耗目标系统资源,因此在访问大量页面时,爬虫需要考虑到规划、负载等问题。

那么我们怎么用python来实现一个爬虫呢?
python已经为我们包装好了几个建立爬虫非常有用的库
针对爬虫爬取的范围,或者说作用,python提供了不用尺寸的爬虫库

爬取网页 玩转网页爬取网站 爬取系列网站爬取全网
小规模,数据量小 爬取速度不敏感中规模,数据规模较大 爬取速度敏感大规模,搜索引擎 爬取速度关键
Request库Scrapy库定制开发

在大部分情况下,requests库已经足够我们使用
那么requests库的基本使用方法是怎样的呢?

Requests

requests库的get方法可以让我们根据传入的url获取到该url的页面源代码

requests.get (url, params=None, **kwargs)

url: 拟获取页面的url链接
params: url中的额外参数,字典或字节流格式,可选
**kwargs: 12个控制访问的参数

//我们首先得导入requests库到python文件中  
import requests
//下面的url表示我们要爬取的页面链接
url = "http://www.baidu.com"
//使用requests库的get方法爬取该url
r = requests.get(url)
//将返回的状态码打印出来
print(r.status_code)

r.status_code: HTTP请求的返回状态,200表示成功,404表示失败
r.text: HTTP响应内容的字符串形式,即,url对应的页面内容
r.encoding: 从HTTP header中猜测的响应内容的编码方式
r.apparent_encoding: 从内容分析出相应内容的编码方式(备选编码方式)
r.content: HTTP响应内容的二进制形式

如果文件显示不正确,可以输入下面这行:

r.encoding = r.apparent_encoding

爬虫爬取的页面不是每次都会成功的,那么失败的时候python就会给我们返回对应的异常,在requests库中,也定义了以下几种可能出现的异常

异常说明
requests.ConnectionError网络连接错误异常,如DNS查询失败,拒绝连接等
requests.HTTPErrorHTTP错误异常
requests.URLRequiredURL缺失异常
requests.TooManyRedirects超过最大重定向次数,产生的重定向异常
requests.ConnestTimeout连接远程服务超时异常
requests.Timeout请求URL超时,产生超时异常

爬取网页的通用代码框架

可以用raise_for_status方法来处理异常

import requests

def getHTMLText(url):
	try:
		r = requests.get(url, timeout=30)
		r = raise_for_status() #如果状态不是200,引发HTTPError异常
		r.encoding = r.apparent_encoding
		return r.text
	except:
		return "产生异常"

if __name__ == "__main__":
	url = "http://www.baidu.com"
	print(getHTTPText(url))

刚才我们使用requests库的get方法来过得页面的源代码,但是实际上,requests不仅仅是一个get方法,根据http协议中的一下几种方法:

HTTP方法说明
GET请求URL位置的资源
HEAD请求页面的头部信息
POST请求向URL位置的资源后附加新的数据
PUT请求向URL位置存储一个资源,覆盖原URL位置的资源
PATCH请求局部更新URL位置的资源,即改变该处资源的部分内容
DELETE请求删除URL位置存储的资源

requests中也定义了很多种请求页面的方法

HTTP的方法和requests库的方法是一一对应的

比如: HEAD 即 requests.head(url)

import requests

url = 'http://httpbin.org/get'
r = requests.head(url)  
print(r.headers)  #r.headers展示头部信息

#POST的方法  
#附加字符ABC 自动存入data字段下   
r = requests.post('http://httpbin.org/post', data = 'ABC')
print(r.text)

#附加字典会自动放入from(表单)中
payload = {'keys1': 'value1', 'keys2': 'value2'}
r = requests.post('http://httpbin.org/post', data = payload)
print(r.text)

Requests库的基本方法是requests方法,该方法通过传入一个method参数,决定以对应的请求方式来访问url页面

requests.request (method, url, **kwargs)

method: 使用的请求方法
url: 请求的页面链接
**kwargs: 控制访问的参数,均为可选项

params: 是字典或字节序列,可以作为参数增加到url中
params 对URL进行修改

kv = {'key1': 'value1', 'key2': 'value2'}  
r = requests.request('GET', 'http://python123.io/ws', params=kv)
print(r.url)

此时请求的页面中带有kv的所有参数

data 是字典/字节序列/文件对象
表示传入的url附加参数

r = requests.request('POST', 'http://python123.io/ws', data=kv)
body = '主体内容'
r = requests.request('POST', 'http://python123.io/ws', data=body)

json

r = requests.request('POST', 'http://python123.io/ws', json=kv)
headers 是字典,表示HTTP的定制头

根据传入的headers参数requests库会包装请求页面的头

hd = {'user-agent': 'Chrome/10'}  
 # 修改user-agent为Chrome/10表示用chrome10版本来请求页面  
r = requests.request('POST', 'http://python123.io/ws', headers=hd)
cookies的形式是解析字典或CookieJar

表示Requests中的cookie

files是字典类型的,用于传输文件
fs = {'file': open('data.xls', 'rb')}
r = requests.request('POST', 'http://python123.io/ws', files=fs)
# 向某一个链接提交某一个文件  
timeout用于设定超时时间,秒为单位
r = requests.request('GET', 'http://wwww.baidu.com', timeout=10)
proxies是字典类型,设定访问代理服务器,可以增加登录认证
pxs = { 'http': 'http://user:pass@10.10.10.1:1234'
		'https': 'https://10.10.10.1:4321'	}
r = requests.request('GET', 'http://www.baidu.com', proxies=pxs)
allow_redirects: True/False, 默认为True,重定向开关
stream: True/False, 默认为True, 默认内容立即下载开关
verify: True/False, 默认为True,认证SSL证书开关
cert: 本地SSL证书路径
import requests

requests.request(method, url, **kwargs)
requests.post(url, data=None, json=None, **kwargs) 
requests.head(url, **kwargs)
requests.put(url, data=None, **kwargs)
requests.patch(url, data=None, **kwargs)
requests,delete(url, **kwargs)
requests.get (url, params=None, **kwargs)
# data: 字典,字节序列,文件,Request的内容  
# json: JSON格式的数据,Request的内容  
# **kwargs: 11个控制访问的参数  
# post,put,patch,delete很难成功

Robots协议

Robots Exclusion Standdard 网络爬虫排除标准
作用: 告知爬虫哪些页面可以爬取,哪些不行
形式: 在网站根目录下的robots.txt文件
不是所有的网站都有robots.txt文件,对于这些网站,可以爬取全部网页

实例

爬取京东

>>> import requests
>>> r = requests.get("https://item.jd.com/2967929.html")
>>> r.status_code
200
>>>r.encoding
'gbk'
>>> r.text[:1000]

爬取亚马逊

>>> r = requests.get("https://www.amazon.cn/gp/product/B01M8L5Z3Y")
>>> r.status_code
503
>>> r.encoding
'ISO-8859-1'
>>> r.encoding = r.apparent_encoding
>>> r.request.headers
{'User-Agent': 'python-requests/2.22.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}

# 模拟浏览器Mozilla/5.0登录
>>> kv = {'User-agent':'Mozilla/5.0'}
>>> r = requests.get(url, headers = kv)
>>> r.status_code
200
>>> r.request.headers
{'User-agent': 'Mozilla/5.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}

百度360搜索关键词提交

百度的关键词接口:
http://www.baidu.com/s?wd=keyword
360的关键词接口:
http://www.so.com/s?q=keyword


>>> import requests

# baidu
>>> kv = {'wd':'python'}
>>> r = requests.get("http://www.baidu.com/s", params=kv)
>>> r.status_code
200


# 360
>>> kv = {'q': 'python'}
>>> r = requests.get("http://www.so.com/s", params=kv)
>>> r.status_code
200
>>> r.request.url
'https://www.so.com/s?q=python'
>>> len(r.text)
349760

网络图片的爬取

import requests
import os
url = "https://img.ivsky.com/img/bizhi/pre/201909/25/haitun-004.jpg"
root = "/home/harden/python-practice/requests_learn/"
path = root + url.split('/')[-1]
try:
	if not os.path.exists(root):
		os.mkdir(root)
	if not os.path.exists(path):
		r = requests.get(url)
		with open(path, 'wb') as f:
			f.write(r.content)
			f.close()
			print("文件保存成功")
	else:
		print("文件已存在")
except:
	print("爬取失败")

以上代码保存在download_picture.py

实例5:IP地址归属地的自动查询

>>> import requests
>>> url = "http://www.ip138.com/iplookup.asp?ip="
>>> r = requests.get(url + '202.204.80.112')
>>> r.status_code
200


BeautifulSoup

>>> import requests
>>> from bs4 import BeautifulSoup
>>> r = requests.get("https://python123.io/ws/demo.html")  
>>> demo = r.text
>>> soup = BeautifulSoup(demo, "html.parser")
>>> print(soup.prettify())

BeautifulSoup库的理解

>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup("<html>data</html>", "html.parser")
>>> soup2 = BeautifulSoup(open("/home/Harden/python_practice/markdown/u.html"), "html.parser")
解析器使用方法条件
bs4的HTML解析器BeautifulSoup(mk,‘html.parser’)安装bs4库
lxml的HTML解析器BeautifulSoup(mk,‘lxml’)pip install lxml
lxml的XML解析器BeautifulSoup(mk,‘xml’)pip install lxml
html5lib的解析器BeautifulSoup(mk,‘html5lib’)pip install html5lib

BeautifulSoup类的基本元素

基本元素说明
Tag标签,最基本的信息组织单元,分别用< >和</>表明开头和结尾
Name标签的名字,< p >…< /p>的名字是’p’,格式: < tag>.name
Attributes标签的属性,字典形式组织,格式: < tag>.attrs
NavigableString标签内非属性字符串,<>…< />中字符串,格式: < tag>.string
Comment标签内字符串的注释部分,一种特殊的Comment类型
>>> soup = BeautifulSoup(demo, "html.parser")
>>> tag = soup.a  #返回第一个a标签
>>> tag
>>> tag.attrs
>>> tag.attrs['class']
>>> tag.attrs['href']
>>> type(tag.attrs)
>>> type(tag)
>>> soup.a.name
>>> soup.a.parent.name
>>> soup.p.parent.name
>>> soup.a
>>> soup.a.string
>>> soup.p
>>> soup.p.string
>>> type(soup.p.string)
>>> newsoup = BeautifulSoup("<b><!--This is a comment--></b><p>This is not a comment</p>", "html.parser")
>>> newsoup.b.string
>>> type(newsoup.b.string)
>>> newsoup.p.string
>>> type(newsoup.p.string)

标签树的下行遍历

属性说明
.contents子节点的列表,将< tag>所有的儿子节点存入列表
.children子节点的迭代类型,与.contents类似,用于循环遍历儿子节点
.descendants子孙节点的迭代类型,包含所有子孙节点,用于遍历列表

.contents和.children只获得当前节点的子节点信息,而.descendants获得所有的子孙节点
迭代类型用在for in 中

>>> soup.head
>>> soup.head.contents
>>> soup.body.contents
>>> len(soup.body.contents)

标签数的上行遍历

属性说明
.parent节点的父亲标签
.parents节点的父辈标签的迭代类型,用于循环便利父辈节点
>>> soup = BeautifulSoup(demo, "html.parser")

>>> soup.title.parent
<head><title>This is a python demo page</title></head>
>>> soup.html.parent
>>> soup.parent # 说明soup的父亲是空的
>>>
>>> soup = BeautifulSoup(demo,"html.parser")
>>> for parent in sou.a.parents:
		if parent is None:
			print(parent)
		else:
			print(parent.name)

标签树的平行遍历
平行遍历发生在同一个父节点下的各节点间

属性说明
.next_sibling返回按照HTTP文本顺序的下一个平行节点标签
.previous_sibling返回按照HTML文本顺序的上一个平行节点标签
.next_siblings迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
.previous_siblings迭代类型,返回按照HTML文本顺序的前续所有平行节点标签

迭代类型只能用在for / in 类型中

>>> soup = BeautifulSoup(demo, "html.parser")
>>> soup.a.next_sibling
' and '
>>> soup.a.next_sibling.next_sibling
<a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>
>>> soup.a.previous_sibling
'Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\n'
>>> soup.a.previous_sibling.previous_sibling
>>> soup.a.parent
bs4的prettify()方法
>>> soup = BeautifulSoup(demo, "html.parser")
>>> soup.prettify()
>>> print(soup.a.prettify())
<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">
 Basic Python
</a>
JSON
"key" : "value"
"key" : ["value1","value2"]
"key" : {"subkey" : "subvalue"
		"subkey2" : "subvalues2"}
YAML

用 缩进 来表达所属信息
用 - 来表达并列关系
用 | 表示整块数据

name : 
	newName : 你好  
	oldName : Hello  
key : 
	subkey : subvalue
good : 			#表达并列关系  
-北京理工大学  
-延安自然科学院  

# |表示整块数据
text: |		#学校介绍
北京理工大学创立于~~~

<>.find_all(name,attrs,recursrve,string,**kwargs)

返回一个列表,储存查找的结果
name: 对标签名称的检索字符串
attrs: 对标签属性值的检索字符串,可标注属性检索
recursive: 是否对子孙全部检索,默认为True,如果为False,则只对儿子节点检索
string: <>…</>中字符串区域的检索字符串

# 查找a标签  
soup.find_all('a')

# 查找a和b标签  
# 把a和b作为第一个参数,用列表形式传输  
soup.find_all(['a','b'])

# 若参数为True则给出所有标签的信息
for tag in soup.find_all(True):
	print (tag.name)

#只显示以b开头的标签  
import re		#正则表达式库
for tag in soup.find_all(re.compile('b')):
	print (tag.name)

# 检索带有course属性值的标签  
soup.find_all('p','course')
[<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a> and <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>.</p>]

# 查找id值为link1的标签
soup.find_all(id='link1')

# 查找以link开头的标签 
import re
soup.find_all(id=re.compile('link'))

# string  
soup.find_all(string = "Basic Python")
['Basic Python']

# 检索带有python的字符串  
import re
soup.find_all(string = re.compile("python"))
['This is a python demo page', 'The demo python introduces several python courses.']

>>> for link in soup.find_all('a'):
...     print(link.get('href'))
http://www.icourse163.org/course/BIT-268001
http://www.icourse163.org/course/BIT-1001870001
>>>

< tag>(…)等价于 < tag>.find_all(…)
soup.(…)等价于 soup.find_all(…)

方法说明
<>.find()搜索且只返回一个结果,字符串类型,同.find_all()参数
<>.find_parents()在父辈节点中搜索,返回列表类型,同.find_all()参数
<>.find_parent()在父辈节点中返回一个结果,字符串类型,同.find()参数
<>.find_next_siblings()在后续平行节点中搜索,返回列表类型,同.find_all()参数
<>.find_next_sibling()在后续平行节点中返回一个结果,字符串类型,同.find()参数
<>.find_previous_siblings()在前序平行节点中搜索,返回列表类型,同.find_all()参数
<>.find_previous_sibling()在前序平行节点中返回一个结果,字符串类型,同.find()参数

视频资源:嵩天

作者github仓库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值