爬虫
爬虫的分类:
通用:
聚焦:数据解析
增量式:监测
http:客户端和服务器端进行数据交互的形式
证书密钥加密:
什么是证书?
证书种包含的是经过数字签名的公钥
反爬:
robots
UA伪装
请求载体的身份标识
在headers种应用一个字典(请求头信息:UA)
动态加载的数据
如何处理动态请求参数:
封装到一个字典中,字典需要作用到data或者params
数据解析
回顾:总结了编码的流程
指定url
发起请求
获取响应数据
数据解析
持久化存储
数据解析的作用
用于获取页面中局部的页面源码数据
如何实现数据解析
正则
bs4(独有)
xpath(最为通用)
pyquery(自学)
数据解析的通用原理是什么?
标签定位
将标签中间存储的文本数据或者其属性值进行捕获
正则解析
需求:爬取糗事百科中的图片数据
确认了页面中没有动态加载数据的存在
import requests
import os
import re
from urllib import request
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
}
封装一个通用的url模板(不可变)
url = 'https://www.qiushibaike.com/pic/page/%d/'
dirName = './qiutuLibs'
if not os.path.exists(dirName):
os.mkdir(dirName)
for page in range(1,3):
print('正在爬取第{}页的图片数据......'.format(page))
#拼接成了某一个页码对应的完整的url
new_url = format(url%page)
#获取页面源码数据(字符串)
page_text = requests.get(url=new_url,headers=headers).text
#数据解析:图片img标签中的src的属性值解析出来
ex = '
img_src_list = re.findall(ex,page_text,re.S)
for img_src in img_src_list:
#就是一个完整的图片地址
img_src = 'https:'+img_src
img_name = img_src.split('/')[-1]
img_path = dirName+'/'+img_name
request.urlretrieve(img_src,img_path)
print(img_name,'下载成功!!!')
bs4解析
环境的安装:
pip install bs4
pip install lxml
bs4解析原理
实例化一个BeautifulSoup的对象,且将即将被解析的页面源码加载到该对象中
使用该对象中的属性或者方法进行标签定位和数据提取
BeautifulSoup对象的实例化方式:lxml就是一款解析器
BeautifulSoup(fp,'lxml'):将本地存储的html文档加载到该对象中
BeautifulSoup(page_text,'lxml'):将互联网上获取的html源码加载到该对象中
将本地的test.html文档中相关的数据进行解析
from bs4 import BeautifulSoup
fp = open('./test.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')
soup
实现标签的定位
soup.title <title>测试bs4</title> soup.div <div> <p>百里守约</p> </div> 总结: soup.tagName:返回的就是页面中第一次出现的tagName标签(返回的是一个单数) find函数的用法:属性定位 soup.find('tagName',attrName='value') 注意:返回的是单数 soup.find('div',class_='song') <div class="song"> <p>李清照</p> <p>王安石</p> <p>苏轼</p> <p>柳宗元</p> <a href="http://www.song.com/" target="_self" title="赵匡胤"> <span>this is span</span> 宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a> <a class="du" href="">总为浮云能蔽日,长安不见使人愁</a> <img alt="" src="http://www.baidu.com/meinv.jpg"/> </div> soup.find_all('tagName'):定位所有的tagName的标签 soup.find_all('tagName',attrName='value'):属性定位 注意:返回值是列表 soup.find_all('div') <div class="tang"> <ul> <li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li> <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li> <li><a alt="qi" href="http://www.126.com">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li> <li><a class="du" href="http://www.sina.com">杜甫</a></li> <li><a class="du" href="http://www.dudu.com">杜牧</a></li> <li><b>杜小月</b></li> <li><i>度蜜月</i></li> <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li> </ul> </div> select('选择器'):根据选择器进行标签定位且返回的是复数(列表) 类选择器,id选择器,标签选择器,层级选择器 层级选择器:>表示一个层级,空格表示多个层级 soup.select('.tang') [<div class="tang"> <ul> <li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li> <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li> <li><a alt="qi" href="http://www.126.com">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li> <li><a class="du" href="http://www.sina.com">杜甫</a></li> <li><a class="du" href="http://www.dudu.com">杜牧</a></li> <li><b>杜小月</b></li> <li><i>度蜜月</i></li> <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li> </ul> </div>] soup.select('.tang > ul > li') [<li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>, <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>, <li><a alt="qi" href="http://www.126.com">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li>, <li><a class="du" href="http://www.sina.com">杜甫</a></li>, <li><a class="du" href="http://www.dudu.com">杜牧</a></li>, <li><b>杜小月</b></li>, <li><i>度蜜月</i></li>, <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li>] soup.select('.tang li') [<li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>, <li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>, <li><a alt="qi" href="http://www.126.com">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li>, <li><a class="du" href="http://www.sina.com">杜甫</a></li>, <li><a class="du" href="http://www.dudu.com">杜牧</a></li>, <li><b>杜小月</b></li>, <li><i>度蜜月</i></li>, <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li>] 取数据(属性值和标签中存储的文本数据) soup.p.string '百里守约' soup.p.text '百里守约' soup.find('div',class_='song').text '\n李清照\n王安石\n苏轼\n柳宗元\n\nthis is span\n\t\t宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱\n总为浮云能蔽日,长安不见使人愁\n\n' text和string的区别? string获取的是标签中直系的文本内容 text获取的是标签中所有的文本内容 取属性: tag['attrName'] for a in soup.select('.tang > ul > li > a'): print(a['href']) http://www.baidu.com http://www.163.com http://www.126.com http://www.sina.com http://www.dudu.com http://www.haha.com 需求:爬取三国演义小说所有内容 url = 'http://www.shicimingju.com/book/sanguoyanyi.html' page_text = requests.get(url=url,headers=headers).text #使用bs4进行数据解析(章节标题&内容) soup = BeautifulSoup(page_text,'lxml') a_list = soup.select('.book-mulu > ul > li > a') fp = open('sanguo.txt','w',encoding='utf-8') for a in a_list: title = a.string detail_url = 'http://www.shicimingju.com'+a['href'] #对详情页的url发起请求解析出章节内容 detail_page_text = requests.get(url=detail_url,headers=headers).text detail_soup = BeautifulSoup(detail_page_text,'lxml') content = detail_soup.find('div',class_='chapter_content').text
fp.write(title+':'+content+'\n')
print(title,'保存成功!!!')
fp.close()
soup.TagName
soup.find
soup.find_all
soup.select
tag.string/text
tag['attrName']
答辩
需求文档
项目背景
项目功能的介绍
展示
业务逻辑
数据量级 >=1w
数据类型
咨询
电商
金融
医疗器械
......
分工
xpath解析
环境安装:pip install lxml
解析原理:
实例化一个etree类型的对象,且将即将被解析的页面源码数据加载到该对象中
调用该对象中的xpath方法结合着不同的xpath表达式进行标签定位和数据提取
实例化对象:
etree.parse(fileName)
etree.HTML(page_text)
from lxml import etree
from lxml.html.clean import tree
tree = etree.parse('test.html')
基于标签定位的xpath表达式
tree.xpath('/html/head/meta')
[]
tree.xpath('//meta')
[<Element meta at 0x1e9a1d27848>]
xpath方法返回值永远是一个列表
xpath表达式中最左侧的/和//的区别是什么?
/表示我们必须从根标签进行定位
//表示我们可以从任意位置标签定位
tree.xpath('//div')
[<Element div at 0x1e9a21ed748>,
<Element div at 0x1e9a1e269c8>,
<Element div at 0x1e9a1e26608>]
属性定位
tree.xpath('//div[@class="song"]')
[<Element div at 0x1e9a1e269c8>]
索引定位
索引值是从1开始
在xpath表达式中非最左侧的/和//的区别?
/表示一个层级
//表示多个层级
tree.xpath('//div[@class="tang"]/ul/li[3]')
[<Element li at 0x1e9a1d27a88>]
tree.xpath('//div[@class="tang"]//li[3]')
[<Element li at 0x1e9a1d27a88>]
取文本
/text():获取的是标签下直系的文本数据
//text():获取的是标签下所有的文本数据
tree.xpath('//div[@class="tang"]//li[5]/a/text()')
['杜牧']
string_list = tree.xpath('//div[@class="tang"]//text()')
''.join(string_list)
'\n\t\t\n\t\t\t清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村\n\t\t\t秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山\n\t\t\t岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君\n\t\t\t杜甫\n\t\t\t杜牧\n\t\t\t杜小月\n\t\t\t度蜜月\n\t\t\t凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘\n\t\t\n\t'
取属性
tree.xpath('//div[@class="tang"]//li[5]/a/@href')
['http://www.dudu.com']
需求:爬取boss中的岗位信息(岗位名称,薪资,公司名称,岗位描述)
url = 'https://www.zhipin.com/c101010100/?query=python爬虫&page=%d'
fp = open('boss.txt','w',encoding='utf-8')
for page in range(1,3):
new_url = format(url%page)
page_text = requests.get(url=new_url,headers=headers).text
#xpath的数据解析
tree = etree.HTML(page_text) #tree中存储的是整张页面对应的页面源码数据
li_list = tree.xpath('//div[@class="job-list"]/ul/li')
for li in li_list:
job_title = li.xpath('./div/div[1]/h3/a/div[1]/text()')[0]#li中存储的是局部的li标签对应的页面源码数据
salary = li.xpath('./div/div[1]/h3/a/span/text()')[0]
detail_url = 'https://www.zhipin.com'+li.xpath('./div/div[1]/h3/a/@href')[0]
company_name = li.xpath('.//div[@class="company-text"]/h3/a/text()')[0]
detail_page_text = requests.get(url=detail_url,headers=headers).text
detail_tree = etree.HTML(detail_page_text)
job_desc = detail_tree.xpath('//*[@id="main"]/div[3]/div/div[2]/div[2]/div[1]/div//text()')
job_desc = ''.join(job_desc)
fp.write(job_title+':'+salary+':'+company_name+':'+job_desc+'\n\n\n')
fp.close()
处理中文乱码
url = 'http://pic.netbian.com/4kmeinv/index_%d.html'
for page in range(1,6):
if page == 1:
new_url = 'http://pic.netbian.com/4kmeinv/'
else:
new_url = format(url%page)
response = requests.get(url=new_url,headers=headers)
response.encoding = 'utf-8'
page_text = response.text
tree = etree.HTML(page_text)
li_list = tree.xpath('//*[@id="main"]/div[3]/ul/li')
for li in li_list:
img_src = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0]
img_name = li.xpath('./a/b/text()')[0]
img_name = img_name.encode('iso-8859-1').decode('gbk')
http://pic.netbian.com/uploads/allimg/180703/142018-15305988184e63.jpg 姜璐4k壁纸
http://pic.netbian.com/uploads/allimg/190713/100152-15629833120209.jpg 克拉女神-蓓颖 风度娴雅
http://pic.netbian.com/uploads/allimg/190608/130131-1559970091ea9b.jpg 双手托腮的美女4k壁纸图
http://pic.netbian.com/uploads/allimg/190427/210756-1556370476a05f.jpg 欣怡4k壁纸
http://pic.netbian.com/uploads/allimg/190328/210949-155377858946d0.jpg 克拉女神 晓晓4k壁纸384
https://www.aqistudy.cn/historydata/ 爬取所有的城市名称
url = 'https://www.aqistudy.cn/historydata/'
page_text = requests.get(url=url,headers=headers).text
tree = etree.HTML(page_text)
hot_cities = tree.xpath('//div[@class="bottom"]/ul/li/a/text()')
all_cities = tree.xpath('//div[@class="bottom"]/ul/div[2]/li/a/text()')
大大滴增强xpath表达式的通用性
cities = tree.xpath('//div[@class="bottom"]/ul/div[2]/li/a/text() | //div[@class="bottom"]/ul/li/a/text()')
print(cities)
['北京', '上海', '广州', '深圳', '杭州', '天津', '成都', '南京', '西安', '武汉', '阿坝州', '安康', '阿克苏地区', '阿里地区', '阿拉善盟', '阿勒泰地区', '安庆', '安顺', '鞍山', '克孜勒苏州', '安阳', '蚌埠', '白城', '保定', '北海', '宝鸡', '北京', '毕节', '博州', '白山', '百色', '保山', '白沙', '包头', '保亭', '本溪', '巴彦淖尔', '白银', '巴中', '滨州', '亳州', '长春', '昌都', '常德', '成都', '承德', '赤峰', '昌吉州', '五家渠', '昌江', '澄迈', '重庆', '长沙', '常熟', '楚雄州', '朝阳', '沧州', '长治', '常州', '潮州', '郴州', '池州', '崇左', '滁州', '定安', '丹东', '东方', '东莞', '德宏州', '大理州', '大连', '大庆', '大同', '定西', '大兴安岭地区', '德阳', '东营', '黔南州', '达州', '德州', '儋州', '鄂尔多斯', '恩施州', '鄂州', '防城港', '佛山', '抚顺', '阜新', '阜阳', '富阳', '抚州', '福州', '广安', '贵港', '桂林', '果洛州', '甘南州', '固原', '广元', '贵阳', '甘孜州', '赣州', '广州', '淮安', '海北州', '鹤壁', '淮北', '河池', '海东地区', '邯郸', '哈尔滨', '合肥', '鹤岗', '黄冈', '黑河', '红河州', '怀化', '呼和浩特', '海口', '呼伦贝尔', '葫芦岛', '哈密地区', '海门', '海南州', '淮南', '黄南州', '衡水', '黄山', '黄石', '和田地区', '海西州', '河源', '衡阳', '汉中', '杭州', '菏泽', '贺州', '湖州', '惠州', '吉安', '金昌', '晋城', '景德镇', '金华', '西双版纳州', '九江', '吉林', '即墨', '江门', '荆门', '佳木斯', '济南', '济宁', '胶南', '酒泉', '句容', '湘西州', '金坛', '鸡西', '嘉兴', '江阴', '揭阳', '济源', '嘉峪关', '胶州', '焦作', '锦州', '晋中', '荆州', '库尔勒', '开封', '黔东南州', '克拉玛依', '昆明', '喀什地区', '昆山', '临安', '六安', '来宾', '聊城', '临沧', '娄底', '乐东', '廊坊', '临汾', '临高', '漯河', '丽江', '吕梁', '陇南', '六盘水', '拉萨', '乐山', '丽水', '凉山州', '陵水', '莱芜', '莱西', '临夏州', '溧阳', '辽阳', '辽源', '临沂', '龙岩', '洛阳', '连云港', '莱州', '兰州', '林芝', '柳州', '泸州', '马鞍山', '牡丹江', '茂名', '眉山', '绵阳', '梅州', '宁波', '南昌', '南充', '宁德', '内江', '南京', '怒江州', '南宁', '南平', '那曲地区', '南通', '南阳', '平度', '平顶山', '普洱', '盘锦', '蓬莱', '平凉', '莆田', '萍乡', '濮阳', '攀枝花', '青岛', '琼海', '秦皇岛', '曲靖', '齐齐哈尔', '七台河', '黔西南州', '清远', '庆阳', '钦州', '衢州', '泉州', '琼中', '荣成', '日喀则', '乳山', '日照', '韶关', '寿光', '上海', '绥化', '石河子', '石家庄', '商洛', '三明', '三门峡', '山南', '遂宁', '四平', '商丘', '宿迁', '上饶', '汕头', '汕尾', '绍兴', '三亚', '邵阳', '沈阳', '十堰', '松原', '双鸭山', '深圳', '朔州', '宿州', '随州', '苏州', '石嘴山', '泰安', '塔城地区', '太仓', '铜川', '屯昌', '通化', '天津', '铁岭', '通辽', '铜陵', '吐鲁番地区', '铜仁地区', '唐山', '天水', '太原', '台州', '泰州', '文昌', '文登', '潍坊', '瓦房店', '威海', '乌海', '芜湖', '武汉', '吴江', '乌兰察布', '乌鲁木齐', '渭南', '万宁', '文山州', '武威', '无锡', '温州', '吴忠', '梧州', '五指山', '西安', '兴安盟', '许昌', '宣城', '襄阳', '孝感', '迪庆州', '锡林郭勒盟', '厦门', '西宁', '咸宁', '湘潭', '邢台', '新乡', '咸阳', '新余', '信阳', '忻州', '徐州', '雅安', '延安', '延边州', '宜宾', '盐城', '宜昌', '宜春', '银川', '运城', '伊春', '云浮', '阳江', '营口', '榆林', '玉林', '伊犁哈萨克州', '阳泉', '玉树州', '烟台', '鹰潭', '义乌', '宜兴', '玉溪', '益阳', '岳阳', '扬州', '永州', '淄博', '自贡', '珠海', '湛江', '镇江', '诸暨', '张家港', '张家界', '张家口', '周口', '驻马店', '章丘', '肇庆', '中山', '舟山', '昭通', '中卫', '张掖', '招远', '资阳', '遵义', '枣庄', '漳州', '郑州', '株洲']
需求文档的定制
糗事百科的段子内容和作者(xpath的管道符)名称进行爬取,然后存储到mysql中or文本
http://sc.chinaz.com/jianli/free.html爬取简历模板
爬取一个你感兴趣的网站数据