数据解析-xpath

引入

xpath解析是我们在爬虫中最常用也是最通用的一种数据解析方式,由于其高效且简介的解析方式受到了广大程序员的喜爱。在后期学习scrapy框架期间,也会再次使用到xpath解析。

环境安装

 

    • pip install lxml

 

解析原理

 

    • 使用通用爬虫爬取网页数据

 

    • 实例化etree对象,且将页面数据加载到该对象中

 

    • 使用xpath函数结合xpath表达式进行标签定位和指定数据提取

 

测试页面数据

  1. 百里守约

  2.  
  3. 李清照

  4. 王安石

  5. 苏轼

  6. 柳宗元

  7.  
  8.  
  9.  
  10. 清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村
  11. 秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山
  12. 岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君
  13. 杜甫
  14. 杜牧
  15. 杜小月
  16. 度蜜月
  17. 凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘
  18.  
  19.  

常用xpath表达式

  1. 属性定位:
  2. #找到class属性值为song的div标签
  3. //div[@class="song"]
  4. 层级&索引定位:
  5. #找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a
  6. //div[@class="tang"]/ul/li[2]/a
  7. 逻辑运算:
  8. #找到href属性值为空且class属性值为du的a标签
  9. //a[@href="" and @class="du"]
  10. 模糊匹配:
  11. //div[contains(@class, "ng")]
  12. //div[starts-with(@class, "ta")]
  13. 取文本:
  14. # /表示获取某个标签下的文本内容
  15. # //表示获取某个标签下的文本内容和所有子标签下的文本内容
  16. //div[@class="song"]/p[1]/text()
  17. //div[@class="tang"]//text()
  18. 取属性:
  19. //div[@class="tang"]//li[2]/a/@href

etree对象实例化

  1. - 本地文件:tree = etree.parse(文件名)
  2. tree.xpath("xpath表达式")
  3. - 网络数据:tree = etree.HTML(网页内容字符串)
  4. tree.xpath("xpath表达式")

实战案例

- 项目需求:解析58二手房的相关数据

  1. #解析出一级页面的标题和二级页面的价格和描述
  2. import requests
  3. from lxml import etree
  4. headers = {
  5. 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
  6. }
  7. url = 'https://bj.58.com/changping/ershoufang/?utm_source=sem-baidu-pc&spm=105916147073.26420796294&PGTID=0d30000c-0000-17fc-4658-9bdfb947934d&ClickID=3'
  8. page_text = requests.get(url=url,headers=headers).text
  9. tree = etree.HTML(page_text)
  10. li_list = tree.xpath('//ul[@class="house-list-wrap"]/li')
  11. data = []
  12. for li in li_list:
  13. #解析标题
  14. title = li.xpath('.//div[@class="list-info"]/h2/a/text()')[0]
  15. detail_page_url = li.xpath('.//div[@class="list-info"]/h2/a/@href')[0]
  16. if detail_page_url.split('//')[0] != 'https:':
  17. detail_page_url = 'https:'+detail_page_url
  18. detail_text = requests.get(url=detail_page_url,headers=headers).text
  19. tree = etree.HTML(detail_text)
  20. #解析二级页面的描述和价格
  21. desc = ''.join(tree.xpath('//div[@id="generalDesc"]//div[@class="general-item-wrap"]//text()')).strip(' \n \t')
  22. price = ''.join(tree.xpath('//div[@id="generalExpense"]//div[@class="general-item-wrap"]//text()')).strip(' \n \t')
  23. dic = {
  24. 'title':title,
  25. 'desc':desc,
  26. 'price':price
  27. }
  28. data.append(dic)
  29. #进行持久化存储
  30. print(data)

- 项目需求:解析图片数据:http://pic.netbian.com/4kmeinv/

  1. import requests
  2. from lxml import etree
  3. url = 'http://pic.netbian.com/4kmeinv/'
  4. headers = {
  5. 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
  6. }
  7. response = requests.get(url=url,headers=headers)
  8. #获取页面原始编码格式
  9. print(response.encoding)
  10. page_text = response.text
  11. tree = etree.HTML(page_text)
  12. li_list = tree.xpath('//div[@class="slist"]/ul/li')
  13. for li in li_list:
  14. img_url = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0]
  15. img_name = li.xpath('./a/img/@alt')[0]
  16. img_name = img_name.encode('iso-8859-1').decode('gbk')
  17. print(img_url,img_name)

- 项目需求:下载煎蛋网中的图片数据:http://jandan.net/ooxx

  1. import requests
  2. from lxml import etree
  3. from fake_useragent import UserAgent
  4. import base64
  5. import urllib.request
  6. url = 'http://jandan.net/ooxx'
  7. ua = UserAgent(verify_ssl=False,use_cache_server=False).random
  8. headers = {
  9. 'User-Agent':ua
  10. }
  11. page_text = requests.get(url=url,headers=headers).text
  12. #查看页面源码:发现所有图片的src值都是一样的。
  13. #简单观察会发现每张图片加载都是通过jandan_load_img(this)这个js函数实现的。
  14. #在该函数后面还有一个class值为img-hash的标签,里面存储的是一组hash值,该值就是加密后的img地址
  15. #加密就是通过js函数实现的,所以分析js函数,获知加密方式,然后进行解密。
  16. #通过抓包工具抓取起始url的数据包,在数据包中全局搜索js函数名(jandan_load_img),然后分析该函数实现加密的方式。
  17. #在该js函数中发现有一个方法调用,该方法就是加密方式,对该方法进行搜索
  18. #搜索到的方法中会发现base64和md5等字样,md5是不可逆的所以优先考虑使用base64解密
  19. #print(page_text)
  20. tree = etree.HTML(page_text)
  21. #在抓包工具的数据包响应对象对应的页面中进行xpath的编写,而不是在浏览器页面中。
  22. #获取了加密的图片url数据
  23. imgCode_list = tree.xpath('//span[@class="img-hash"]/text()')
  24. imgUrl_list = []
  25. for url in imgCode_list:
  26. #base64.b64decode(url)为byte类型,需要转成str
  27. img_url = 'http:'+base64.b64decode(url).decode()
  28. imgUrl_list.append(img_url)
  29. for url in imgUrl_list:
  30. filePath = url.split('/')[-1]
  31. urllib.request.urlretrieve(url=url,filename=filePath)
  32. print(filePath+'下载成功')
  1. - 项目需求:解析出所有城市名称https://www.aqistudy.cn/historydata/
    1. import requests
    2. from lxml import etree
    3. url = 'https://www.aqistudy.cn/historydata/'
    4. headers = {
    5. 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
    6. }
    7. response = requests.get(url=url,headers=headers)
    8. #获取页面原始编码格式
    9. print(response.encoding)
    10. page_text = response.text
    11. tree = etree.HTML(page_text)
    12. li_list = tree.xpath('//div[@class="bottom"]/ul/li | //div[@class="bottom"]/ul//li')
    13. for li in li_list:
    14. city_name = li.xpath('./a/text()')[0]
    15. city_url = 'https://www.aqistudy.cn/historydata/'+li.xpath('./a/@href')[0]
    16. print(city_name,city_url)
posted @ 2021-03-23 13:46  好吗,好  阅读(98)  评论(0)    收藏  举报