一. urllib
urllib是python中自带的一个基于爬虫的模块
作用:可以使用代码模拟浏览器发起请求
使用流程:
- 指定url
- 发起请求
- 获取页面数据
- 持久化存储
1. 第一个urllib爬虫程序
# 需求: 爬取搜狗首页的页面数据
import urllib.request
# 1. 指定url
url = 'https://www.sogou.com/'
# 2. 发起请求:urlopen可以根据指定的url发起请求,并返回一个响应对象
response = urllib.request.urlopen(url=url)
# 3. 获取页面数据:read函数返回的就是响应对象中存储的页面数据
page_text = response.read()
# 4. 进行持久化存储
with open('./sougou.html', 'wb') as f:
f.write(page_text)
print("Done")
2. urllib编码处理
# 需求:爬去指定词条所对应的页面数据
import urllib.request
import urllib.parse
# 指定url
url = 'https://www.sogou.com/web?query='
# url特性:url不可以存在非ASCII编码的字符数据,汉字并不在ASCII编码当中
word = urllib.parse.quote("宝马")
url += word
# 发请求
response = urllib.request.urlopen(url=url)
# 获取页面数据
page_text = response.read()
# 持久化存储
with open('./bmw.html', 'wb') as f:
f.write(page_text)
3. urllib的post请求
# urllib模块发起的post请求
# 需求:爬取百度翻译的翻译结果
import urllib.request
import urllib.parse
# 1. 指定url
url = 'https://fanyi.baidu.com/sug'
# post请求携带的参数进行处理
# 流程:
# 1). 将post请求参数封装到字典
data = {
'kw': "苹果"
}
# 2). 使用parse模块中的urlencode(返回值类型为str)进行编码处理
query = urllib.parse.urlencode(data)
# 3). 将步骤2的编码结果转换成byte类型
data = query.encode()
# 2. 发起post请求:urlopen函数的data参数表示的就是经过处理之后的post请求携带的参数
response = urllib.request.urlopen(url=url, data=data)
print(response.read())
二. requests模块
requests是python原生的一个基于网络请求的模块,模拟浏览器发起请求
1. requests-get请求:
1)简单的get请求
import requests
# 需求:爬取搜狗首页的页面数据
url = 'https://www.sogou.com/'
# 发起get请求,get方法会返回请求成功的相应对象
response = requests.get(url=url)
# 获取响应中的数据值:text可以获取响应对象中字符串形式的页面数据
page_data = response.text
# response对象中其他的重要属性
# content或取得时response对象中二进制(byte)类型的页面数据
# print(response.content)
# 返回一个响应状态码
# print(response.status_code)
# 返回响应头信息
# print(response.headers)
# 获取请求的url
# print(response.url)
# 持久化操作
with open('./sougou_requests.html', 'w',encoding='utf-8') as f:
f.write(page_data)
2)requests携带参数的get请求
方式1:
# requests模块处理携带参数的get请求
# 需求:指定一个词条,获取搜狗搜索结果所对应的页面数据
# 1. 指定url
url = 'https://www.sogou.com/web?query=宝马&ie=utf-8'
response = requests.get(url=url)
page_text = response.text
with open('./bmw_requests.html', 'w', encoding='utf-8') as f:
f.write(page_text)
方式2:
# requests模块处理携带参数的get请求
# 需求:指定一个词条,获取搜狗搜索结果所对应的页面数据
url = 'https://www.sogou.com/web'
# 将参数封装到字典中
params = {
'query': '宝马',
'ie': 'utf-8'
}
response = requests.get(url=url, params=params)
print(response.text)
3)自定义请求头信息
# 自定义请求头信息
import requests
url = 'https://www.sogou.com/web'
params = {
'query': '宝马',
'ie': 'utf-8'
}
# 自定义请求头信息
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
}
response = requests.get(url=url, params=params, headers=headers)
print(response.text)
2. requests的post请求
import requests
# 1. 指定post请求的url
url = 'https://accounts.douban.com/login'
# 2. 发起post请求
data = {
'source': 'movie',
'redir': 'https://movie.douban.com/',
'form_email' : 'xxx@qq.com',
'form_password' : 'xxx',
'login' : '登录'
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
}
response = requests.post(url=url, data=data)
# 3. 获取响应对象中的页面数据
page_text = response.text
# 4. 持久化操作
with open('./douban_request.html', 'w', encoding='utf-8') as f:
f.write(page_text)
3. ajax的get请求
import requests
url = 'https://movie.douban.com/j/chart/top_list?'
# 封装ajax的get请求中携带的参数
params = {
'type' : '13',
'interval_id' : '100:90',
'action': '',
'start': '0',
'limit': '20',
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
}
response = requests.get(url, params=params, headers=headers)
print(response.text)
4. ajax的post请求
import requests
# 1. 指定url
post_url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
# 处理post请求的参数
data = {
'cname': '',
'pid': '',
'keyword': '上海',
'pageIndex': 1,
'pageSize': 10
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
}
# 2. 发起基于ajax的post请求
response = requests.post(url=post_url, data=data, headers=headers)
print(response.text)
5. 综合实战
import requests
import os
# 创建一个文件夹
if not os.path.exists('./zhihu_pages'):
os.mkdir('./zhihu_pages')
word = input('enter a word: ')
# 动态指定页码的范围
start_pageNum = int(input('enter a start pageNum: '))
end_pageNum = int(input('enter a end pageNum: '))
# 指定url:设计成一个具有通用的url
url = 'http://zhihu.sogou.com/zhihu'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
}
for page in range(start_pageNum, end_pageNum+1):
params = {
'query': word,
'page': page,
'ie': 'utf-8'
}
response = requests.get(url=url, params=params, headers=headers)
# 获取响应中的页面数据
page_text = response.text
# 进行持久化存储
filename = word + str(page) + '.html'
filePath = 'zhihu_pages/' + filename
with open(filePath, 'w', encoding='utf-8') as f:
f.write(page_text)
print("文件第%s页数据写入成功" % page)
6. requests携带cookie
cookie作用:服务器端使用cookie来记录客户端的状态信息
实现流程:1.执行登陆操作(获取cookie);2.在发起个人主页请求时,需要将cookie携带到该请求中
import requests
# 获取session对象
session = requests.session()
# 1. 发起登录请求:将cookie获取,并存储到session对象中
login_url = 'https://accounts.douban.com/login'
data = {
'source': 'None',
'redir': 'https://www.douban.com/people/186539740/',
'form_email' : 'xxxx@qq.com',
'form_password' : 'xxx',
'login' : '登录'
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
}
# 使用session发起post请求
login_response = session.post(url=login_url, data=data, headers=headers)
# 2. 对个人主页发起请求(session(cookie)),获取相应页面数据
url = 'https://www.douban.com/people/186539740/'
response = session.get(url=url, headers=headers)
page_text = response.text
with open('./douban_person1.html', 'w', encoding='utf-8') as f:
f.write(page_text)
7. requests模块的代理操作
代理分类:1.正向代理:代替客户端获取数据;2.反向代理:代理服务器端提供数据
免费代理ip的网站提供商:www.goubanjia.com; 快代理;西祠代理
import requests
url = 'https://www.baidu.com/s?ie=utf-8&wd=ip'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
}
# 将代理ip封装到字典当中
proxy = {
'http': '39.137.77.66:8080'
}
# 更换网路IP
response = requests.get(url=url, proxies=proxy, headers=headers)
with open('./proxy1.html', 'w', encoding='utf-8') as f:
f.write(response.text)
8. 数据解析
1)正则表达式
# 需求:使用正则对糗事百科中的图片数据进行解析和下载
import requests
import re
import os
# 指定url
url = 'https://www.qiushibaike.com/pic/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
}
# 发起请求
response = requests.get(url=url, headers=headers)
# 获取页面数据
page_text = response.text
# 数据解析
img_list = re.findall('<div class="thumb">.*?<img src="(.*?)".*?>.*?</div>', page_text, re.S)
# 创建一个存储图片数据的文件夹
if not os.path.exists('./imgs_qiushi'):
os.mkdir('imgs_qiushi')
for url in img_list:
# 将图片的url进行拼接,拼接成一个完整的url
img_url = 'https:' + url
# 持久化存储:存储的是图片的数据,并不是url
# 获取图片二进制的数据值
img_data = requests.get(url=img_url, headers=headers).content
imgName = url.split('/')[-1]
imgPath = 'imgs_qiushi/' + imgName
with open(imgPath, 'wb') as f:
f.write(img_data)
print(imgName + "写入完成")
2)xpath
xpath在爬虫中的使用流程:
(1) 下载:pip install lxml
(2) 导包:from lxml import etree
(3) 创建etree对象进行指定数据的解析
- 本地:etree = etree.parse("本地文件路径")
- etree.xpath("xpath表达式")
- 网络:etree = etree.HTML("网络请求到的页面数据")
- etree.xpath("xpath表达式")
常用的xpath表达式:
(1)属性定位:
# 找到class属性值为song的div标签:"//div[@class='song']"
(2)层级&索引定位:
# 找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a:"//div[@class='tang']/ul/li[2]/a"
(3)逻辑运算:
# 找到href属性值为空且class属性值为du的a标签:"//div[@href='' and @class='du']"
(4)模糊匹配:
# "//div[contains(@class, 'ng')]"
# "//div[starts-with(@class, 'ta')]"
(5)取文本:
# /表示获取某个标签下的文本内容
# //表示获取某个标签下的文本内容和所有子标签下的文本内容
# "//div[@class='song']/p[1]/text()"
# "//div[@class='tang']//text()"
(6)取属性:
# "//div[@class='tang']//li[2]/a/@href"
# 需求:使用xpath对段子网中的段子内容和标题进行解析,并持久化存储
import requests
from lxml import etree
# 1. 指定url
url = 'https://ishuo.cn/joke'
# 2. 发起请求
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
}
response = requests.get(url=url, headers=headers)
# 3. 获取页面内容
page_text = response.text
# 4. 数据解析
tree = etree.HTML(page_text)
# 获取所有的li标签,
li_list = tree.xpath("//div[@id='list']/ul/li")
with open('./duanzi.txt', 'w', encoding='utf-8') as f:
for li in li_list:
content = li.xpath("./div[@class='content']/text()")[0]
title = li.xpath("./div[@class='info']/a/text()")[0]
# 5. 持久化
f.write(title + ":" + content + "\n\n")
3)bs4
核心思想:将html文档转换成Beautiful对象,然后调用该对象中的属性和方法进行html稳定指定内容的定位查找。
属性和方法:
(1)根据标签名查找
soup.a # 只能找到第一个符合要求的标签
(2)获取属性
soup.a.attrs # 获取a所有的属性和属性值,返回一个字典
soup.a.attrs['href'] # 获取href属性
soup.a['href'] # 也可以简写为这种形式
(3)获取内容
soup.a.string
soup.a.text
soup.a.get_text()
注意:如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
(4)find:找到第一个符合要求的标签
soup.find('a') # 找到第一个符合要求的
soup.find('a', title='xxx')
soup.find('a', alt='xxx')
soup.find('a', class='xxx')
soup.find('a', id='xxx')
(5)find_all:找到所有符合要求的标签
soup.find_all('a')
soup.find_all(['a', 'b']) # 找到所有的a和b标签
soup.find_all('a', limit=2) # 限制前两个
(6)根据选择器选择指定的内容
select:soup.select('#feng')
- 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
层级选择器:
div .dudu #lala ,meme .xixi
div > p > a > .lala
注意:select选择器返回永远是列表,需要通过下标提取指定的对象
# 需求:爬取古诗文网中三国小说里的标题和内容
import requests
from bs4 import BeautifulSoup
url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
}
# 根据url获取页面内容中指定的标题所对应的文章内容
def get_content(url):
content_page = requests.get(url=url, headers=headers).text
soup = BeautifulSoup(content_page, 'lxml')
div = soup.find('div', class_='chapter_content')
return div.text
page_text = requests.get(url=url, headers=headers).text
soup = BeautifulSoup(page_text, 'lxml')
a_list = soup.select('.book-mulu > ul > li > a')
with open('./threekingdoms.txt', 'w', encoding='utf-8') as f:
for a in a_list:
title = a.string
content_url = 'http://www.shicimingju.com' + a['href']
content = get_content(content_url)
f.write(title + ":\n" + content + "\n\n\n")
print(title + ": 已被写入")
9. 处理页面动态加载数据的爬取
1)selenum:三方库。可以实现让浏览器完成自动化的操作
(1)环境搭建
a. 安装: pip install selenium
b. 获取浏览器的驱动程序:
谷歌浏览器驱动下载地址:chromedriver.storage.googleapis.com/index.html
下载的驱动程序必须和浏览器的版本统一,对照表参照:http://blog.youkuaiyun.com/huilan_same/article/details/51896672
from selenium import webdriver
# 创建一个浏览器对象executable_path驱动的路径
b = webdriver.Chrome(executable_path='./chromedriver')
#get方法可以指定一个url,让浏览器进行请求
url = 'https://www.baidu.com'
b.get(url)
# 使用下面的方法,查找指定的元素进行操作即可
# find_element_by_id 根据id找节点
# find_elements_by_name 根据name找
# find_elements_by_xpath 根据xpath查找
# find_elements_by_tag_name 根据标签找
# find_elements_by_class_name 根据class名字查找
# 让百度进行指定词条的搜索
text = b.find_element_by_id('k