2-爬虫-数据解析之bs4与xpath、cookie反爬、代理反爬
- 正则(几乎不用)
- bs4
- xpath(***)
- pyquery(自学)
在爬虫中为什么需要使用数据解析?
- 数据解析作用:帮助我们可以实现聚焦爬虫(爬取局部数据)
- 聚焦爬虫实现流程:
- 1.指定url
- 2.发起请求
- 3.获取响应数据
- 4.数据解析
- 5.持久化存储
- 数据解析通用原理
- 1.html作用?
- html主要的作用就是用来展示数据
- 2.我们要解析的数据其实都是存储在
- html的标签之中
- 标签的属性
- 1.html作用?
- 通用原理:
- 定位标签
- 获取标签中的数据或者标签的属性值
- 环境安装:pip install bs4,pip install lxml
- bs4解析原理
- 实例化一个BeautifulSoup的对象,且将被解析的页面数据加载到该对象中
- 调用BeautifulSoup对象中相关的方法和属性进行标签定位和相关数据的提取
- BeautifulSoup的对象实例化方式:
- 方式1:BeautifulSoup(fp,'lxml')
- 可以将本地存储的html文件中的数据进行数据解析
- 方式2:BeautifulSoup(page_text,'lxml')
- 可以将互联网上请求到的页面数据进行数据解析
- 方式1:BeautifulSoup(fp,'lxml')
- 标签定位:
- soup.tagName:可以定位到第一次出现的该标签
- 属性定位:
- soup.find('tagName',attrName='attrValue')
- 注意:find只可以定位到第一次出现的该标签
- soup.find_all('tagName',attrName='attrValue')
- 注意:find_all可以定位到符合条件所有的标签,返回值一定是列表
- soup.find('tagName',attrName='attrValue')
- 选择器定位:select('选择器')
- id,类,层级选择器
- 层级选择器:
- 大于号:表示一个层级
- 空格:表示多个层级
- 取文本
- tag.string:获取标签直系的文本内容
- tag.text:获取标签下所有的文本内容
- 取属性
- tag['attrName']
from bs4 import BeautifulSoup fp = open('./test.html','r',encoding='utf-8') soup = BeautifulSoup(fp,'lxml') soup.div soup.find('div',class_="song") soup.find_all('div',class_='song') soup.find_all('a',id='feng') soup.select('#feng') soup.select('.song') soup.select('.tang > ul > li > a') soup.select('.tang a') [<a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a>, <a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a>, <a alt="qi" href="http://www.126.com">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a>, <a class="du" href="http://www.sina.com">杜甫</a>, <a class="du" href="http://www.dudu.com">杜牧</a>, <a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a>] soup.find('a',id="feng").text '凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘' soup.find('div',class_='song').text '\n李清照\n王安石\n苏轼\n柳宗元\n\nthis is span\n\t\t宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱\n总为浮云能蔽日,长安不见使人愁\n\n' soup.find('a',id="feng")['href'] 'http://www.haha.com'
-
需求:将三国演义整片内容爬取和保存
import requests from bs4 import BeautifulSoup headers = { 'User-Agent':'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36' } fp = open('sanguo.txt','w',encoding='utf-8') url = 'http://www.shicimingju.com/book/sanguoyanyi.html' page_text = requests.get(url=url,headers=headers).text #数据解析:章节标题+详情页的url soup = BeautifulSoup(page_text,'lxml') a_list = soup.select('.book-mulu > ul > li > a') for a in a_list: title = a.string detail_url = 'http://www.shicimingju.com'+a['href'] #对详情页的url发起请求获取详情页的页面源码数据 page_text_detail = requests.get(url=detail_url,headers=headers).text #数据解析:章节内容 detail_soup = BeautifulSoup(page_text_detail,'lxml') content = detail_soup.find('div',class_='chapter_content').text fp.write(title+':'+content) print(title,'下载保存成功!!!') fp.close()
xpath解析
-
-
环境安装:pip install lxml
-
xpath解析的原理:
-
html标签是基于树状的结构存在的
-
1.实例化一个etree的对象,且将被解析的数据加载到该对象
-
2.调用etree对象中的xpath方法结合着不同形式的xpath表达式进行标签定位和数据提取
-
-
etree对象的实例化两种方式:
-
方式1:etree.parse('filename')
-
方式2:etree.HTML(page_text)
-
-
-
标签定位
-
最左侧的/:一定要从根标签开始进行指定标签的定位
-
非最左侧的/:表示一个层级
-
非最左侧的//:表示多个层级
-
最左侧的//:可以从任意位置定位指定标签(常用)
-
属性定位://tagName[@attrName="attrValue"]
-
索引定位://tagName[index],注意索引是从1开始
-
模糊匹配:
-
//div[contains(@class, "ng")]:定位到class属性值中包含ng的div标签
-
//div[starts-with(@class, "ta")]:定位到class属性值是以ta开头的标签
-
-
-
取文本
-
/text():可以将标签中直系的文本内容取出,且返回的列表元素只有一个
-
//text():可以将标签中所有的文本内容取出,且返回的列表元素为多个
-
-
取属性
-
/@attrName
-
from lxml import etree tree = etree.parse('test.html') tree <lxml.etree._ElementTree at 0x11387ad48> #定位title标签 tree.xpath('/html/head/title') tree.xpath('/html//title') tree.xpath('//title') [<Element html at 0x113db1ec8>] #定位class属性值为cong的div标签 tree.xpath('//div[@class="song"]') [<Element div at 0x113fa00c8>] tree.xpath('//a[@id="feng"]/text()')[0] '凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘' ''.join(tree.xpath('//div[2]//text()')) '\n\t\t李清照\n\t\t王安石\n\t\t苏轼\n\t\t柳宗元\n\t\t\n\t\t\tthis is span\n\t\t宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱\n\t\t总为浮云能蔽日,长安不见使人愁\n\t\t\n\t' tree.xpath('//a[@id="feng"]/@href')[0] 'http://www.haha.com'
-
爬取糗事百科的段子内容
url_model = 'https://www.qiushibaike.com/text/page/%d/' for page in range(1,14): url = format(url_model%page) page_text = requests.get(url=url,headers=headers).text #数据解析:段子作者+内容 tree = etree.HTML(page_text) #定位标签 div_list = tree.xpath('//div[@class="col1 old-style-col1"]/div') for div in div_list: #局部的数据解析 #每次循环使用的div表示就是页面中定位到的指定div标签(包含了要解析的内容) #注意:./就是xpath方法的调用者 author = div.xpath('./div[1]/a[2]/h2/text()')[0] #想要从div表示的指定标签数据中进行指定数据的解析 content = div.xpath('./a[1]/div/span//text()') content = ''.join(content) print(author,content)
-
拓展:
-
可以将文字数据进行语音合成
-
可以使用百度AI进行语音合成
-
-


-
爬取图片数据
import os dirName = 'GirlsLib' if not os.path.exists(dirName): os.mkdir(dirName) url_model = 'http://pic.netbian.com/4kmeinv/index_%d.html' for page in range(1,6): if page == 1: url = 'http://pic.netbian.com/4kmeinv/' else: url = format(url_model%page) response = requests.get(url=url,headers=headers) response.encoding = 'gbk' page_text = response.text #数据解析:图片的名称+图片的地址 tree = etree.HTML(page_text) li_list = tree.xpath('//*[@id="main"]/div[3]/ul/li') for li in li_list: title = li.xpath('./a/img/@alt')[0]+'.jpg' img_src = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0] #对图片地址发起请求 img_data = requests.get(url=img_src,headers=headers).content img_path = dirName+'/'+title with open(img_path,'wb') as fp: fp.write(img_data) print(title,'写入成功!')
-
想要解析出携带标签的文本内容,如何实现?
-
-
爬取雪球网中的咨询数据
import requests headers = { 'User-Agent':'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36', } url = 'https://xueqiu.com/statuses/hot/listV2.json?since_id=-1&max_id=72813&size=15' requests.get(url,headers=headers).json() #问题:没有获取数据,原因一定是没有严格模拟浏览器上网的流程
-
在爬虫中处理cookie的方式:
-
手动处理
-
从抓包工具中将cookie封装到headers字典中
-
局限性:如果cookie过了有效时长,则该种方式会失效
-
-
-
自动处理
-
使用session机制。
-
1.可以获取一个session对象
-
2.可以基于该对象进行请求的发送
-
在请求发送的过程中,如果产生了cookie,则cookie会被存储到该对象中。
-
如果cookie被存储到了session对象中,则再次使用session对象发请求,则该次请求就是携带者cookie进行的请求发送
-
-
注意:Session对象在使用的时候,至少需要被调用两次。
-
-
sess = requests.Session() #创建了一个sessio对象 first_url = 'https://xueqiu.com/' #该次请求会产生cookie,且cookie存储到了session对象中 sess.get(url=first_url,headers=headers) url = 'https://xueqiu.com/statuses/hot/listV2.json?since_id=-1&max_id=72813&size=15' #该次请求就是携带cookie进行的请求发送 sess.get(url,headers=headers).json()
代理反爬
-
代理反爬
-
什么是代理
-
就是代理服务器
-
-
代理服务器的作用:
-
可以进行请求和响应的转发/拦截
-
-
在爬虫中为何需要使用代理?
-
如果我们使用爬虫对一个网站在段时间内发起一个高频的请求,该网站会检测出这个异常的现象,且会将异常的请求ip获取,将ip加入到黑名单,然后该ip在近期就无法再次对该网站进行网络访问。
-
如果本机ip被对方服务器加入到了黑名单,则我们就可以使用代理服务器进行请求转发,最终对方服务器获取的请求ip就是代理服务器的不在我们自己本机的。
-
-
代理的匿名度:
-
透明:对方服务器知道你使用了代理,也知道你的真实ip
-
匿名:对方服务器知道你使用了代理,但是不知道你的真是ip
-
高匿:不知道使用了代理,也不知道你的真实ip
-
-
代理的类型
-
http:只能转发http协议的请求
-
https:只能转发https协议的请求
-
-
from lxml import etree #没有使用代理的情况 url = 'https://www.sogou.com/web?query=ip' page_text = requests.get(url=url,headers=headers).text tree = etree.HTML(page_text) tree.xpath('//*[@id="ipsearchresult"]//text()')
#使用代理的情况 url = 'https://www.sogou.com/web?query=ip' page_text = requests.get(url=url,headers=headers,proxies={'https':'114.239.119.157:42559'}).text tree = etree.HTML(page_text) tree.xpath('//*[@id="ipsearchresult"]//text()')
-
需求:
-
对一个网站发起高频请求,然后让其将本机ip加入黑名单,构建代理池处理
-
import random #提取代理精灵代理服务器ip+port的方法 all_proxy = [] #代理池 url = 'http://ip.11jsq.com/index.php/api/entry?method=proxyServer.generate_api_url&packid=1&fa=0&fetch_key=&groupid=0&qty=51&time=1&pro=&city=&port=1&format=html&ss=5&css=&dt=1&specialTxt=3&specialJson=&usertype=2' page_text = requests.get(url,headers=headers).text tree = etree.HTML(page_text) data_list = tree.xpath('//body//text()') for data in data_list: dic = {} dic['https'] = data all_proxy.append(dic) url_model = 'http://www.521609.com/daxuemeinv/list8%d.html' all_data = [] for page in range(1,23): url = format(url_model%page) page_text = requests.get(url=url,headers=headers,proxies=random.choice(all_proxy)).text tree = etree.HTML(page_text) li_list = tree.xpath('//*[@id="content"]/div[2]/div[2]/ul/li') for li in li_list: detail_url = 'http://www.521609.com'+li.xpath('./a[1]/@href')[0] page_text_detail = requests.get(detail_url,headers=headers).text all_data.append(page_text_detail) print(len(all_data))
作业
-
爬取站长素材中的简历模板

浙公网安备 33010602011771号