python爬虫笔记
记录时间:2021年1月31日
理论知识
1、数据解析
(1)分类
- 正则
- bs4
- xpath(***)
(2)原理概述
- 解析的局部文本内容都会在标签之间或者对应的属性中进行存储
- 第一步:进行指定标签的定位
- 第二步:标签或者标签对应的属性中存储的数据值进行提取
(3)编码流程
1、指定url
2、发起请求
3、获取响应数据
4、数据解析
5、持久化存储
实战部分
1、正则解析
需求1:爬取糗事百科中糗图板块下热图图片
如何爬取图片数据?
当我们用requests发送请求后,我们可以获得响应response,其中:
- response.text——字符串
- response.content——二进制
- json()——对象类型
保存图片就可以用response.content存储二进制形式的数据。
爬取单独1页内容:
import requests
import re
import os
if __name__ == '__main__':
# 创建一个文件夹存储图片
if not os.path.exists('./糗事百科'):
os.mkdir('./糗事百科')
url = 'https://www.qiushibaike.com/imgrank/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.56'
}
response = requests.get(url=url, headers=headers)
html = response.text
all_src = re.findall(
'<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>',
html, re.S)
for src in all_src:
# 拼接url
url = 'http:' + src
# 获取图片二进制
img = requests.get(url=url, headers=headers).content
# 生成图片名称
img_name = src.split('/')[-1]
# 生成图片路径
img_path = './糗事百科/' + img_name
# 保存图片
with open(img_path,'wb') as fp:
fp.write(img)
print(img_name+'下载完成')
分页爬取:
import requests
import re
import os
if __name__ == '__main__':
# 创建一个文件夹存储图片
if not os.path.exists('./糗事百科'):
os.mkdir('./糗事百科')
base_url = 'https://www.qiushibaike.com/imgrank/page/%d/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.56'
}
for page_num in range(1, 11):
# 每一页创建一个文件夹分别存储
if not os.path.exists('./糗事百科/' + str(page_num)):
os.mkdir('./糗事百科/' + str(page_num))
newurl = format(base_url % page_num)
html = requests.get(url=base_url, headers=headers).text
all_src = re.findall(
'<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>',
html, re.S)
for src in all_src:
# 拼接url
url = 'http:' + src
# 获取图片二进制
img = requests.get(url=url, headers=headers).content
# 生成图片名称
img_name = src.split('/')[-1]
# 生成图片路径
img_path = './糗事百科/' + str(page_num) + '/' + img_name
# 保存图片
with open(img_path, 'wb') as fp:
fp.write(img)
print(img_name + '下载完成')
2、bs4解析
操作步骤:
- 第一步:实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中
- 第二步:通过调用BeautifulSoup对象中相关的属性和方法进行标签定位和数据提取
BeautifulSoup对象中相关的属性和方法:
——假设soup = BeautifulSoup(html.text, 'lxml')
- soup.tagName:返回的是html中第一次出现tagName的对应的标签,例如:soup.div
- soup.find():
(1) 括号内填写标签名,例如:soup.find('div'),结果同soup.div;
(2)属性定位,例如:soup.find('div', class_/id/attr = 'xxx') - soup.find_all('tagName'):返回所有满足要求的标签(列表),例如:soup.find_all('div', class_/id/attr = 'xxx')
- select:
—soup.select('某种选择器 (id,class,标签。。。选择器) '):返回一个列表
—层级选择器:
—soup.select(' .classname > ul > li > a'):">"表示的是一个层级
—soup.select(' .classname > ul a'):空格表示多个层级 - 获取标签之间的文本数据:
—soup.div.text :可以获取某一标签下所有的文本内容
—soup.div.string :可以获取某一标签直系的文本内容
—soup.div.get_text() :可以获取某一标签下所有的文本内容 - 获取标签中的属性值:
—soup.a['href']:获取a标签中href属性的内容
需求2:爬取三国演义小说所有的标题和章节内容
import requests
from bs4 import BeautifulSoup
if __name__ == '__main__':
url = 'https://www.shicimingju.com/book/sanguoyanyi.html'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.56'
}
html = requests.get(url=url, headers=headers)
html.encoding = html.apparent_encoding
soup = BeautifulSoup(html.text, 'lxml')
titles = soup.select('.book-mulu > ul > li')
for title in titles:
print(title.a.text)
book_url = 'https://www.shicimingju.com' + title.a['href']
html = requests.get(url=book_url, headers=headers)
html.encoding = html.apparent_encoding
book_soup = BeautifulSoup(html.text, 'lxml')
text = book_soup.find('div', class_='chapter_content').text.replace(' ', '')
# print(text)
with open('./三国演义/三国演义.txt', 'a', encoding='utf-8') as fp:
fp.write(title.a.text + text + '\n\n')
3、xpath解析
最常用且最便捷高效的一种解析方式。
xpath解析原理:
- 第一步:实例化一种etree的对象,且需要将被解析的页面源码数据加载到该对象中。
- 第二步:调用etree对象中的xpath方法结合xpath表达式实现标签的定位和内容的捕捉
xpath表达式:
- '/html/body/div' :定位到html下body的div标签
- '/html//div' :定位到html下多个层级的div标签
- '//div' :定位到所有的div标签
- '//div[@class=xxx]' :定位到class为“xxx"的div标签
- '//div[@class=xxx]/p[3]' :定位到class为“xxx"的div的第3个p标签(索引是从1开始)
- 取文本:
—'/text()' :取直系文本
—'//text()' :取所有文本 - 取属性:
—'/@attrName' :例如'//div//img/@src',获取div下img的src属性
需求3:爬取58二手房中的房源信息
import requests
from lxml import etree
if __name__ == '__main__':
url = 'https://www.58.com/ershoufang/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.56'
}
html = requests.get(url=url, headers=headers)
tree = etree.HTML(html.text)
# print(html.text)
tr_list = tree.xpath('//*[@id="global"]/table/tr')
for tr in tr_list:
msg = tr.xpath('./td[2]/a/text()')[0]
price = tr.xpath('./td[3]/b/text()')[0] + '万元'
type_ = tr.xpath('./td[4]//text()')[0]+tr.xpath('./td[4]//text()')[1]
size = tr.xpath('./td[5]/b/text()')[0] + '平方米'
with open('./二手房/房源信息.txt', 'a', encoding='utf-8') as fp:
fp.write(msg + ' ' + price + ' ' + type_ + ' ' + size + '\n')
print('保存成功!')
需求4:爬取4k高清图片
通用处理中文乱码的方法:
- img_name.encode('iso-8859-1').decode('gbk')
- response.encoding='utf-8'
import requests
from lxml import etree
if __name__ == '__main__':
url = 'http://pic.netbian.com/4kfengjing/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.56'
}
html = requests.get(url=url, headers=headers)
tree = etree.HTML(html.text)
li_list = tree.xpath('//ul[@class="clearfix"]//li')
for li in li_list:
url = 'http://pic.netbian.com' + li.xpath('./a/img/@src')[0]
filename = li.xpath('./a/b/text()')[0].encode('iso-8859-1').decode('gbk') + '.jpg'
data = requests.get(url=url, headers=headers).content
with open('./风景图片/'+filename,'wb')as fp:
fp.write(data)
print(filename+'保存成功!')
需求5:爬取全国城市名称
import requests
from lxml import etree
if __name__ == '__main__':
url = 'https://www.aqistudy.cn/historydata/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.56'
}
html = requests.get(url=url, headers=headers)
tree = etree.HTML(html.text)
ul_list = tree.xpath('//div[@class="all"]/div[@class="bottom"]/ul[@class="unstyled"]')
with open('./全国城市名称/全国城市名称.txt', 'a', encoding='utf-8') as fp:
for ul in ul_list:
index = ul.xpath('./div[1]/b//text()')[0]
fp.write(index+'\n')
li_list = ul.xpath('./div[2]/li')
for li in li_list:
city = li.xpath('./a/text()')[0]
fp.write(city + ' ')
fp.write('\n')
print('保存成功!')