题外话
- 爬虫相关案例不会详细到一步步放出来,比如获取多个页面的数据,你就去多看几个页面的网址,大概率就能发现他的规律,又或者先获取当前页面的跳转网址,在对获取到的网址再做一次类似的爬取,很多就是一步步轮下去的,而我呈现的是完整的一步到位的代码,所以感觉有跳跃或者有问题,可以勤用print,可以较为直观的看出是哪里有问题。
1、数据解析
上篇中的案例其实主要都是在进行通用爬虫,但对于用户来说,爬取整个页面的信息是冗余的,许多信息是无用数据甚至还需要用户自行去挑选,需要耗费大量的时间和精力,所以数据解析就显得无可或缺。
数据解析的概念:可以将爬取到的数据中指定的数据进行单独提取
作用:实现聚焦爬虫
通用原理:
- 在一张页面中,爬取到的数据往往存储于html文件中
- html文件中,可以通过标签去定位想要获取的数据位置,并进行提取
数据解析技术:
- xpath(通用性最强)
- bs4(python独有,学习成本低)
- 正则表达式(复杂度高)
- pyquery(css语句)
这次主要以xpath技术为主,xpath的编码流程:
- 创建一个etree类型的对象,把被解析的数据加载到该对象中
- 调用etree对象中的xpath函数结合不同形式的xpath表达式进行数据提取
2.案例一
通过新建一个text.html文件,对html进行分析来初步理解xpath进行数据解析的原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <html lang="en"> <head> <meta charset="UTF-8" /> <title>测试bs4</title> </head> <body> <div> <p>百里守约</p> </div> <div class="song"> <p>李清照</p> <p>王安石</p> <p>苏轼</p> <p>柳宗元</p> <a href="http://www.song.com/" title="赵匡胤" target="_self"> <span>this is span</span> 宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a> <a href="" class="du">总为浮云能蔽日,长安不见使人愁</a> <img src="http://www.baidu.com/meinv.jpg" alt="" /> </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 href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li> <li><a href="http://www.sina.com" class="du">杜甫</a></li> <li><a href="http://www.dudu.com" class="du">杜牧</a></li> <li><b>杜小月</b></li> <li><i>度蜜月</i></li> <li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li> </ul> </div> </body> </html>
|
代码中我们需要使用一个新的包lxml,可以通过下述在终端中进行下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| from lxml import etree
tree = etree.parse('test.html')
ret = tree.xpath('/html/head/title')
ret1 = tree.xpath('//title')
ret2 = tree.xpath('//div') ret3 = tree.xpath('//div[@class="song"]') ret4 = tree.xpath('//div[@class="song"]/p')
ret5 = tree.xpath('//a[@id="feng"]/text()') ret6 = tree.xpath('//a//text()')
print(ret7)
|
3. 碧血剑小说
网址:https://www.jinyongwang.net/bi/
结果:将各个章节的标题和内容进行爬取然后存储到文件中
先找到对应的标签的位置

然后右键

即可复制xpath,减少工作量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import requests from lxml import etree from urllib.parse import urljoin url ='https://www.jinyongwang.net/bi/' header = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36', 'referer':'https://www.jinyongwang.net/bi/', 'cookie': 'PHPSESSID=t880k0dcvvjkbgdulcaa25krf6' } response = requests.get(url=url,headers=header) response.encoding='utf-8' page_bi = response.text
tree = etree.HTML(page_bi)
with open('bixuejian.txt','w',encoding='utf-8') as f: li_list = tree.xpath('//*[@id="pu_box"]/div[3]/ul/li') for li in li_list: title = li.xpath('./a/text()')[0] detail = li.xpath('./a/@href')[0] detail_url = urljoin(url, detail) res = requests.get(url=detail_url,headers=header ) res.encoding= 'utf-8' content = res.text detail_tree = etree.HTML(content) text = detail_tree.xpath('//*[@id="vcon"]//p//text()') text_join = ',\n'.join(text).strip() print(title + ' 下载成功')
|

上述就是结果样式
4. 简历爬取
网址= https://sc.chinaz.com/jianli/
下述就是需要得到的xpath

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import requests from lxml import etree page_input = input('请输入搜索页码(1-5):') pages=[] if '-' in page_input: start,end = map(int, page_input.split('-')) pages= list(range(start, end+1)) else: pages = [int(page_input)] for page in (1,2): if page == 1: url = 'https://sc.chinaz.com/jianli/index.html' else: url = 'https://sc.chinaz.com/jianli/index_%d.html'%page print('当前正在爬取第%d页的数据'%page) header = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36', } response = requests.get(url=url, headers=header) response.encoding='utf-8' page_jianli = response.text tree = etree.HTML(page_jianli) div_list = tree.xpath('//*[@id="container"]/div') for div in div_list: title = div.xpath('./p/a/text()')[0] detail_url = div.xpath('./a/@href')[0] jianli_response = requests.get(url=detail_url,headers=header) jianli_response.encoding= 'utf-8' page_down = jianli_response.text down_tree = etree.HTML(page_down) down_url = down_tree.xpath('//*[@id="down"]/div[2]/ul/li[1]/a/@href')[0] down_response = requests.get(url=down_url,headers=header) down_content = down_response.content name = './jianli/'+ title+ '.rar' with open(name,'wb') as f: f.write(down_content)
|
ps(pthon):
- 序列化:json.dumps()
- 反序列化:json.load()