请求模块 - Requests
Requests 是唯一的一个非转基因的 Python HTTP 库,人类可以安全享用。Requests 允许你发送纯天然,植物饲养的 HTTP/1.1 请求,无需手工劳动。你不需要手动为 URL 添加查询字串,也不需要对 POST 数据进行表单编码。Keep-alive 和 HTTP 连接池的功能是 100% 自动化的,一切动力都来自于根植在 Requests 内部的 urllib3。(解释源自python-requests.org)
安装:
pip install requestes
以一个简单的抓取百度首页的爬虫为例:
# -*- coding: utf-8 -*-
import requests
url = 'http://www.baidu.com'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
response = requests.get(url=url, headers=headers)
content = response.content.decode()
print(content)
注释:
- 接收两个参数: 第一个是URL,第二个是请求头, 这里包含一个User-Agent(用户代理)
- 使用 get 方式进行请求
- 返回的数据使用 response 接收
- 使用 decode() 进行解码(默认使用utf8进行解码), 使用的时候可以加上参数, 指定其编码方式以及时候忽略错误, 比如:
content = response.content.decode('gb2312', 'ignore')
通常情况下,在获取某些get请求的内容而非post请求的内容时,我们只需要将UA修改成一般浏览器的UA就好了,无需增加其他请求头。
网页解析模块 - BeautifulSoup
BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库。它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。Beautiful Soup会帮你节省数小时甚至数天的工作时间。
安装:
pip install bs4
以下示例, 爬取一个简单的静态网页:
# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
import requests
import os
url = 'https://www.dbmeinv.com/'
headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' }
response = requests.get(url=url, headers=headers)
content = response.content.decode()
soup = BeautifulSoup(content, 'html.parser') # 注释1
img_list = soup.find_all(name='img', class_='height_min') # 注释2
for img in img_list: # 注释3
src = img.attrs['src']
title = img.attrs['title'] # 注释4
response = requests.get(url=src, headers=headers)
content = response.content
imagesPath = 'images'
if not os.path.exists(imagesPath):
os.makedirs(imagesPath)
with open('%s/%s.jpg' % (imagesPath, title), 'wb') as f: # 注释5
f.write(content)
- 注释1:这里新建了一个Beautifulsoup对象,它有两个必要的参数,第一个参数是HTML代码对象,比如这里content存储了URL为”https://www.dbmeinv.com/"的这张网页的HTML代码,它是个字符串或者是一个文件句柄第二个参数是HTML解析器,这个解析器可以使用内置标准的"html.parser",也可以安装第三方的解析器,比如lxml和html5lib。 | 解析器 | 使用方法 | 优势 | 劣势 | | —- | —- | —- | —- | | Python标准库 | BeautifulSoup(markup, “html.parser”) | Python的内置标准库执行速度适中文档容错能力强 | Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差 | | lxml HTML 解析器 | BeautifulSoup(markup, “lxml”) | 速度快文档容错能力强 | 需要安装C语言库 | | lxml XML 解析器 | BeautifulSoup(markup, [“lxml”, “xml”]) BeautifulSoup(markup, “xml”) | 速度快唯一支持XML的解析器 | 需要安装C语言库 | | html5lib | BeautifulSoup(markup, “html5lib”) | 最好的容错性以浏览器的方式解析文档生成HTML5格式的文档 | 速度慢不依赖外部扩展 |
比如安装 lxml HTML 解析器: pip install lxml
如果安装不成功, 可以到 Unofficial Windows Binaries for Python Extension Packages 下载 lxml 模块, 比如 lxml-4.1.1-cp35-cp35m-win32.whl
, 下载完成后到下载目录执行 pip install lxml-4.1.1-cp35-cp35m-win32.whl
即可安装。
- 注释2:这里使用了soup对象的一个方法”findall()”,字面理解就是”找出所有的”,那么找出什么,如何定位这个所谓的”什么”?这里就要传入两个参数,第一个是HTML文档的节点名,也可以理解为HTML的标签名;第二个则是该节点的class类名,比如上面代码中,我要找出该网页上所有的img节点,且我需要的img节点的类名为”height_min”, 因为calss和关键字冲突,所以改名`class`。但是对于一些没有class类名的HTML元素我们该如何寻找?
我们还可以用到另一个属性:attrs,比如这里可以写成:
img_list = soup.find_all(name='img', attrs={'class': 'height_min'})
attrs是字典类型,冒号左边为关键字,右边为关键字的值。不一定要通过class来查找某一个元素,也可以通过比如”id”,”name”,”type”等各种HTML的属性,如果想要的元素实在没有其他属性,可以先定位到该元素的父属性,再使用.children
定位到该元素。
- 注释3:注释2返回的是一个列表对象,包含了整张网页上的图片,因此这里用一个循环,分别处理每一张图片。
- 注释4:取出了图片的路径和标题。
- 注释5:这里需要重新请求图片的地址,获得图片二进制的返回值,因为是图片,所以不能用decode()解码,必须以二进制的方式写入,后面的写入模式”wb”,加了个”b”就是表示以二进制的形式。
也可以将解码的工作放到 bs4 中:
response = requests.get(url=url, headers=headers)
soup = BeautifulSoup(response.content, 'html.parser', from_encoding="utf-8")
如果本身是 utf-8
编码,可省略 from_encoding
参数。
数据库模块 - pymysql
可以使用 pymysql 模块, 将爬虫获取到的数据存储到 MySQL 数据库, 例如爬取斗图网1-1000页的图片:
# -*- coding: utf-8 -*-
import requests
import re
import pymysql
# 连接数据库
db = pymysql.connect(host='127.0.0.1', port = 3306, db='test', user='root', passwd='root', charset='utf8')
# 创建游标
cursor = db.cursor()
# 获取斗图王图片
def getImgesList(page = 1):
html = requests.get('http://www.doutula.com/photo/list/?page={}'.format(page)).text
reg = r'data-original="(.*?)".*?alt="(.*?)"'
# S 多行匹配,提升效率
reg = re.compile(reg, re.S)
imagesList = re.findall(reg, html)
for i in imagesList:
cursor.execute("insert into img(`title`, `src`) values ('{}', '{}')".format(i[1], i[0]))
print('正在保存 %s' %i[1])
db.commit()
for i in range(1, 1001):
getImgesList(i)
print('第{}页'.format(i))
- 使用
pymysql.connect
进行数据库连接 - 使用
db.cursor()
创建游标 - 使用
re.compile(reg, re.S)
执行正则匹配 findall()
返回的是括号所匹配到的结果,多个括号就会返回多个括号分别匹配到的结果(得到一个元组数组)- 使用
cursor.execute
执行SQL语句 - 使用
db.commit()
进行数据库提交