在本章中,我们将介绍以下配方:
Web 抓取是将数据从 Web 自动提取为一种格式的过程,以便您可以轻松地分析或使用它。urllib
Python 模块帮助您从 web 服务器下载数据。
要从 web 服务器下载网页,urllib
模块是标准 Python 库的一部分,可以使用urllib
包含从 URL 检索数据的函数。
为了学习基础知识,我们可以使用 Python 交互式终端。在终端窗口中键入python
并按输入。这将打开 Python(Python2.x)交互式终端。
在 Python2.x 和 Python3.x 中,用于执行此操作的命令存在一些差异,主要是使用print
语句。所以请注意语法上的差异。这将有助于我们即将推出的食谱。
urllib
:>>> import urllib
urlopen
方式,您可以下载网页:>>> webpage = urllib.urlopen("https://www.packtpub.com/")
read
方法像读取返回对象一样读取文件:>>> source = webpage.read()
>>> webpage.close()
>>> print source
>>> f = open('packtpub-home.html', 'w')
>>> f.write(source)
>>> f.close
在 Python3 中,urllib
和urllib2
都是urllib
模块的一部分,因此使用urllib
有一些区别。此外,urllib
软件包包含以下模块:
urllib.request
urllib.error
urllib.parse
urllib.robotparser
urllib.request
模块用于使用 Python 3 打开和获取 URL:
urllib
包导入urllib.request
模块:>>> import urllib.request
urlopen
方法获取网页:>>> webpage = urllib.request.urlopen("https://www.packtpub.com/")
read
方法读取对象:>>> source = webpage.read()
>>> webpage.close()
>>> print(source)
>>> f = open('packtpub-home.html', 'wb')
>>> f.write(source)
>>> f.close
Python2 模块urllib
和urllib2
帮助完成 URL 请求相关的工作,但它们都有不同的功能。
urllib
提供urlencode
方法,用于生成GET
请求。但是,urllib2
不支持urlencode
方法。另外,urllib2
可以接受请求对象并修改 URL 请求的头,但urllib
只能接受 URL,不能修改其中的头。
许多网站使用用户代理字符串来识别浏览器并相应地提供服务。由于我们正在使用urllib
访问该网站,它将无法识别该用户代理,并且可能会以奇怪的方式进行操作或失败。因此,在本例中,我们可以为请求指定用户代理。
我们在请求中使用自定义用户代理字符串,如下所示:
>>> import urllib.request
>>> user_agent = ' Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0'
>>> headers = {'User-Agent': user_agent}
>>> request = urllib.request.Request("https://www.packtpub.com/", headers=headers)
urlopen
请求网页:>>> with urllib.request.urlopen(request) as response:
... with open('with_new_user_agent.html', 'wb') as out:
... out.write(response.read())
我们可以利用requests
Python 模块下载文件。requests
模块是 Python 中的简单易用的HTTP 库,具有多种应用程序。此外,它还有助于建立与 web 服务的无缝交互。
首先,您必须安装requests
库。这可以使用pip
通过键入以下命令来完成:
pip install requests
让我们试着用requests
模块下载一个简单的图像文件。打开 Python 2:
requests
库:>>> import requests
get
方法传递 URL 来创建 HTTP 响应对象:>>> response = requests.get("https://rejahrehim.cimg/me/rejah.png")
>>> with open("me.png",'wb') as file:
... file.write(response.content)
如果是一个大文件,response.``content
将是一个大字符串,无法在单个字符串中保存所有数据。在这里,我们使用iter_content
方法将数据分块加载。
stream
:response = requests.get("https://rejahrehim.cimg/me/rejah.png", stream = True)
>>> with open("me.png",'wb') as file:
... for chunk in response.iter_content(chunk_size=1024):
... if chunk:
... file.write(chunk)
这将在 Python3 中工作。另外,请确保在 Python3 环境中安装了所需的库。
正则表达式(re模块)有助于从下载的网页中查找特定的文本模式。正则表达式可用于解析网页中的数据。
例如,我们可以尝试在正则表达式模块的帮助下下载网页中的所有图像。
为此,我们可以编写一个 Python 脚本,用于下载网页中的所有 JPG 图像:
download_image.py
的文件。import urllib2
import re
from os.path import basename
from urlparse import urlsplit
url='https://www.packtpub.com/'
response = urllib2.urlopen(url)
source = response.read()
file = open("packtpub.txt", "w")
file.write(source)
file.close()
patten = '(http)?s?:?(\/\/[^"]*\.(?:png|jpg|jpeg|gif|png|svg))'
for line in open('packtpub.txt'):
for m in re.findall(patten, line):
fileName = basename(urlsplit(m[1])[2])
try:
img = urllib2.urlopen('https:' + m[1]).read()
file = open(fileName, "w")
file.write(img)
file.close()
except:
pass
break
循环的第一个遍历下载网页中的行。第二个for 循环使用正则表达式模式搜索每一行的图像 URL。
如果找到该模式,则使用urlparse
模块中的urlsplit()
方法提取图像的文件名。然后,我们下载图像并将其保存到本地系统。
可以将相同的脚本重写为 Python 3,只需很少的更改:
import urllib.request
import urllib.parse
import re
from os.path import basename
url = 'https://www.packtpub.com/'
response = urllib.request.urlopen(url)
source = response.read()
file = open("packtpub.txt", "wb")
file.write(source)
file.close()
patten = '(http)?s?:?(\/\/[^"]*\.(?:png|jpg|jpeg|gif|png|svg))'
for line in open('packtpub.txt'):
for m in re.findall(patten, line):
print('https:' + m[1])
fileName = basename(urllib.parse.urlsplit(m[1])[2])
print(fileName)
try:
img = urllib.request.urlopen('https:' + m[1]).read()
file = open(fileName, "wb")
file.write(img)
file.close()
except:
pass
break
在 Python 3 中,请求模块和urlparse
模块与urllib
组合为urllib.request
和urllib.parse
。使用正则表达式模式,我们可以解析网页的许多有用信息。
您可以在了解有关正则表达式模块的更多信息 https://docs.python.org/3.7/library/re.html 。
如果网站有表单或收到用户输入,我们必须提交GET
请求或POST
请求。现在,让我们尝试使用 Python 创建GET
请求和 post 请求。查询字符串是向 URL 添加键值对的方法。
在前面的配方中,如果我们在最后一步中删除 try-catch 块,会发生什么?
patten = '(http)?s?:?(\/\/[^"]*\.(?:png|jpg|jpeg|gif|png|svg))'
for line in open('packtpub.txt'):
for m in re.findall(patten, line):
fileName = basename(urlsplit(m[1])[2])
img = urllib2.urlopen('https:' + m[1]).read()
file = open(fileName, "w")
file.write(img)
file.close()
break
由于 URL 格式中的错误,脚本将在几次请求后失败。URL 中出现了一些额外字符,导致urllib
请求失败。
不可能记住哪些字符无效并用百分号手动转义,但内置 Python 模块urllib.parse
具有解决此问题所需的方法。
现在,我们可以尝试通过对请求进行转义/URL 编码来解决这个问题。按如下方式重写脚本:
patten = '(http)?s?:?(\/\/[^"]*\.(?:png|jpg|jpeg|gif|png|svg))'
for line in open('packtpub.txt'):
for m in re.findall(patten, line):
print('https:' + m[1])
fileName = basename(urllib.parse.urlsplit(m[1])[2])
print(fileName)
request = 'https:' + urllib.parse.quote(m[1])
img = urllib.request.urlopen(request).read()
file = open(fileName, "wb")
file.write(img)
file.close()
break
现在我们知道,只要我们有 URL,Python 就可以通过编程方式下载网站。如果我们必须下载多个只在查询字符串中不同的页面,那么我们可以编写一个脚本来完成这项工作,而无需重复运行该脚本,而是在一次运行中下载所需的所有内容。
查看此 URL--https://www.packtpub.com/all?search= &偏移量=12&行=&排序=。这里,定义页码(偏移量**的查询字符串变量是 12 的倍数:
*要下载所有这些页面中的所有图像,我们可以按如下方式重写前面的配方:
import urllib.request
import urllib.parse
import re
from os.path import basename
url = 'https://www.packtpub.com/'
queryString = 'all?search=&offset='
for i in range(0, 200, 12):
query = queryString + str(i)
url += query
print(url)
response = urllib.request.urlopen(url)
source = response.read()
file = open("packtpub.txt", "wb")
file.write(source)
file.close()
patten = '(http)?s?:?(\/\/[^"]*\.(?:png|jpg|jpeg|gif|png|svg))'
for line in open('packtpub.txt'):
for m in re.findall(patten, line):
print('https:' + m[1])
fileName = basename(urllib.parse.urlsplit(m[1])[2])
print(fileName)
request = 'https:' + urllib.parse.quote(m[1])
img = urllib.request.urlopen(request).read()
file = open(fileName, "wb")
file.write(img)
file.close()
break
```*
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。