您当前的位置:首页 > 计算机 > 编程开发 > Python

python爬虫小结(-xpath解析)

时间:10-19来源:作者:点击数:

小结重点

1.url

for i in range(2, 4):
    # 一定要在循环内,否则一直为"https://pic.netbian.com/4kmeinv/index_2.html"
    # 关于为什么后面是/4kmeinv/index_{0}.html 代码后讲解
    url = "https://pic.netbian.com/4kmeinv/index_{0}.html"
    url = url.format(i)

2、乱码

#方法一
#先获取网页的HTML
    #page=requests.get(url=url,headers=headers).text        #乱码了
    respone=requests.get(url=url,headers=headers)
    #手动设定解决乱码
    respone.encoding="utf-8"        #乱码没解决
    page=respone.text


#方法二
   # 通用处理中文乱码的解决方案
        img_name=img_name.encode('iso-8859-1').decode('gbk')
        #print(img_name)
        
        
1. 文字乱码
.encode("iso-8859-1").decode('gbk')
.encode("iso-8859-1").decode('utf-8')
.encode("iso-8859-1")
.encode("utf-8")
都可尝试一下


3. 还有就是文件格式打开,rar问价是二进制文件,"wb"方式打开

 
5. 关于xpath表达式返回空列表:
除了正则表达式错误外,我们也可以检查一下在运行过程中对数据读取的情况是否和我们页面上内容一致

格式化校验:json工具

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

语法:

  • 对象表示为键值对
  • 数据由逗号隔开
  • { }保存对象
  • [ ]保存数组

网址:https://www.json.cn/

requests模块

1.简述get和post

requests主要有两个小的数据请求方式get和post

如何在网页上进行分辨呢?

  • 1.可以直接在检查界面看到请求方式

    在这里插入图片描述
  • 2.在检查界面看看是否有From Data数据,若有就是post,没有就是get

    在这里插入图片描述

2.编码基本流程:

  1. 指定url
  2. 发起请求
  3. 获取响应数据
  4. 持续化储存

3.网址解析

https://movie.douban.com/typerank?type_name=%E5%96%9C%E5%89%A7&type=24&interval_id=100:90
用该网址举三个例子:
#uA伪装
headers={
    'User-Agent':''
}

#例子1
url='https://movie.douban.com/typerank?type_name=%E5%96%9C%E5%89%A7&type=24&interval_id=100:90'
param={}
response=requests.get(url=url,params=param,headers=headers)

#例子2
url='https://movie.douban.com/typerank?'
param={
		"type_name":"%E5%96%9C%E5%89%A7",
		"type":'24',
		"interval_id":'100:90'
			}
response=requests.get(url=url,params=param,headers=headers)

#例子3
param={
		"type_name":"%E5%96%9C%E5%89%A7",
		"type":'24',
			}
response=requests.get(url='https://movie.douban.com/typerank?interval_id=100:90',params=param,headers=headers)

4.request解析

4.1、get请求(params)
在这里插入图片描述

例如爬取:爬取搜狗指定词条对应的搜索结果页面

import requests
if __name__=="__main__":
    url='https://www.sogou.com/web?' #https://www.sogou.com/web?query=你好李焕英
    #处理url携带的参数:封装到字典中
    world=input('请输入搜索内容')
    param={
        'query':world   #query=你好李焕英
    }
    #UA伪装
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'
    }

    #对指定的url发起的请求对应的url是携带参数的,并且请求过程中处理了参数
    #url请求过程中动态拼接了param
    response=requests.get(url=url,params=param,headers=headers)
    page=response.text
    
    #输出文件的命名
    kw=world+'.html'
    with open(kw,'w',encoding='utf-8') as fp:
        fp.write(page)
    print("爬虫完毕")

4.2、post请求

预备知识
首先我们要了解百度翻译的机制(阿贾克斯请求):
 1. url的确定
 2. User-Agent的确定
 3. data数据内容
 4. response数据返回类型
 5. Request Method 请求方式

阿贾克斯(Ajax):当我们在打开一个界面时输入相应的内容,并没有按下回车键,就会自动帮我们搜索相应的结果,这个过程就称为阿贾克斯请求。在电脑端的百度,谷歌等浏览器中经常见到。(我们打开一个界面检查后,进入Network,在网址不改变的情况下看到的新Name就是阿贾克斯请求)

在进行阿贾克斯请求时网址是不变的啊!!!

在进行阿贾克斯请求时网址是不变的啊!!!

在进行阿贾克斯请求时网址是不变的啊!!!

在这里插入图片描述

需求:破解百度翻译

  1. url的确定
  2. Request Method 请求方式
  3. User-Agent的确定
  4. data数据内容
  5. response数据返回类型
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  • post请求(携带了参数)
  • 响应数据是一组json数据
import requests
import json
if __name__=="__main__":
    #1.指定url
   post_url='https://fanyi.baidu.com/sug'
    #2.UA伪装
   headers = {
       'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'
   }
   #post请求参数处理(同get请求一致)
   word=input('请输入一个单词:')
   data={
       'kw':word
   }
    #4.请求发送
   response=requests.post(url=post_url,data=data,headers=headers)
    #5.获取响应数据:json()方法返回的是obj
    #如果确认响应数据是json类型的,才可以使用json()
   page=response.json()
    #持久化存储
   fp=word+'.json'
   filename=open(fp,'w',encoding='utf-8')
   json.dump(page,fp=filename,ensure_ascii=False)
   fp.close()#打开后一定要关闭文件,否则不能在文件中看到存储内容

4.3 json持久化存储
  #4.请求发送
   response=requests.post(url=post_url,data=data,headers=headers)
    #5.获取响应数据:json()方法返回的是obj
    
   #如果确认响应数据是json类型的,才可以使用json()
   page=response.json()
    #持久化存储
   fp=word+'.json'
   filename=open(fp,'w',encoding='utf-8')
   json.dump(page #储存数据
             ,fp=filename	#存储地址
             ,ensure_ascii=False)#是否以ASCLL内容格式存储,由于翻译内容包含汉字,而ASCLL中没有汉字,所以False.
4.4 从json中读取数据

豆瓣电影:

整体的:

import json
import requests
url="https://movie.douban.com/j/chart/top_list?"
header={
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.5211 SLBChan/25"
}
param={
    'type': '24'
    ,'interval_id': '100:90'
    ,'action':''
    ,'start': '0'#爬去开始位置
    ,'limit': '10'#每次爬取数据个数
}
response=requests.get(url=url
                      ,params=param
                      ,headers=header)

page_json=response.json()
print(page_json)

fp = open(file="dou_ban.json",mode='w+',encoding="utf-8")
json.dump(page_json,fp=fp,ensure_ascii=False)
fp.close()
print("爬爬爬over")

这是保存的数据(我们没法用):

在这里插入图片描述

那么----------展开第一个object,哇哇哇!!!

在这里插入图片描述
局部数据代码实现(排名)
import json
import requests
url="https://movie.douban.com/j/chart/top_list?"
header={
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.5211 SLBChan/25"
}
param={
    'type': '24'
    ,'interval_id': '100:90'
    ,'action':''
    ,'start': '0'#爬去开始位置
    ,'limit': '10'#每次爬取数据个数
}
response=requests.get(url=url
                      ,params=param
                      ,headers=header)

movie_json=response.json()
fp = open(file="movie_rank.html",mode='w+',encoding="utf-8")

for each_movie in movie_json:
    json.dump([each_movie['rank'],each_movie['title']], fp=fp, ensure_ascii=False)
    fp.write('\n')

fp.close()
print("爬爬爬over")

这是获取后的:

在这里插入图片描述
整体和局部不同比较
#整体

json.dump(page_json,fp=fp,ensure_ascii=False)

fp.close()
print("爬爬爬over")

#局部

for each_movie in movie_json:
    json.dump([each_movie['rank'],each_movie['title']], fp=fp, ensure_ascii=False)
    fp.write('\n')

fp.close()
print("爬爬爬over")

4.5实例

国药和百度图片:https://www.cdsy.xyz/computer/programme/Python/20221019/cd166617660737323.html

5.数据解析

聚焦爬虫:简单的来说就是爬取目标界面中特定的数据。对于一整页网页数据,我们有时候想要的内容仅仅是某些特定的信息,就像我们拿到某页的网址,仅仅是想要里面的小姐姐的图片,而不想要其他的。那么我们如何针对性的爬取我们所想要的信息呢???那么我们就需要用到数据解析帮助我们

5.1数据解析理论基础

数据解析类别

  • 正则数据解析(支持多种语言)
  • bs4(python独有)
  • xpath(重点讲解)(支持多种语言)

数据解析原理

  • 解析的局部文本内容都会在标签之间或者标签对应的属性中进行存储。
  • 进行指定标签的定位。
  • 标签或者标签对应的属性中储存数据值进行提取(解析)

聚爬编码流程

  1. 指定url
  2. 发起请求
  3. 获取响应数据
  4. 数据解析
  5. 持续化储存
1、xpath解析原理:

1.实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中。

2.调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获。

2、环境的安装:
pip install lxml
3、如何实例化一etree对象:from lxml import entree
  • 1.将本地的html文档中的源码数据加载到etree对象中:
    etree.parse(filrPath)
    
  • 2.可以将从互联网上获取的源码数据加载到该对象中
    etree.HTML('page_text')
    
  • xpath('Xpath表达式')
    
4.xpath表达式
  • / :表示的是从根节点开始定位。表示的是一个层级。

例如:test.html中的根节点是html

#定位到title标签
    r=tree.xpath('/html/head/title')  #从根节点开始一层一层去定位,返回的列表,返回的是element对象,不是具体内容
    print(r)	#输出是列表
    
'''
输出:[<Element title at 0x26ed87de2c0>]
'''


#有几个div,返回列表中就有几个Element
    r = tree.xpath('/html/body/div')  # 从根节点开始一层一层去定位,返回的列表,返回的是element对象,不是具体内容
    print(r)
 
'''
输出:[<Element div at 0x2041d1ee400>, <Element div at 0x2041d1ee480>, <Element div at 0x2041d1ee4c0>]
'''

  • //:表示的是多个层级。可以表示从任意位置开始定位。
 #有几个div,返回列表中就有几个Element
    r = tree.xpath('//div')  # 同
    print(r)
  • 属性定位://div[@class=‘song’] tag[@attrName=“attrValue”]
div[@class='song'] tag[@attrName="attrValue"]

#例子
#属性定位
    r = tree.xpath('//div[@class="song"]')   #[]中括号@是固定格式,返回的是列表
#返回的是[<Element div at 0x2af276df340>]

  • 索引定位://div[@class=“song”]/p[3] 索引是从1开始的。
 # 索引定位
    r = tree.xpath('//div[@class="song"]/p[3]')  # []中索引是从1开始的
    print(r)  #[<Element p at 0x29af6930180>]
  • 取文本:
    • /text() 获取的是标签中直系的文本内容
      # 定位
          r = tree.xpath('//div[@class="tang"]/ul/li[5]/a/text()')  # []中索引是从1开始的
          print(r)  #['杜牧']
          
          r = tree.xpath('//div[@class="tang"]/ul/li[5]/a/text()')[0] #杜牧
      
    • //text() 标签中非直系的文本内容(所有的文本内容)
      # 取文本  //text()
          r = tree.xpath('//div[@class="tang"]/ul/li[5]//text()')  # []中索引是从1开始的
          print(r)		#['杜牧']
      
      
  • 取属性:
    /@attrName ==>img/src
    # 取属性  /@attrName
        r = tree.xpath('//div[@class="song"]/img/@src')  # @src :@属性  /@attrName
        print(r)  #['http://www.baidu.com/meinv.jpg']
        
         r = tree.xpath('//div[@class="song"]/img/@src')[0] #http://www.baidu.com/meinv.jpg
    
5.etree和xpath的认识和使用:实例化
#两种导库方式
from lxml import etree 
from lxml.html import etree

1. 讲本地html文档加载进该对象中
res=etree.parse('./test.html', etree.HTMLParser())#不需要用ope打开
#对于etree.HTMLParser(),暂时不明白原因,期待大家帮助

#返回<lxml.etree._ElementTree at 0x1fb534d6440>

2. 将互联网上的页面源码加载到对象中(较为常用)
response=requests.get(url,headers=header).text
res=etree.HTML(response)#response必须为text

#返回<Element html at 0x1fb531afa80>

6、实战58同城
import requests
from lxml import etree
header = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.5211 SLBChan/25"
}
url = "https://zz.58.com/ershoufang/"
house_text=requests.get(url=url,headers=header).text
#注意一定有.text  否则报错

house_tree=etree.HTML(house_text)#实例化
res=house_tree.xpath("//section[@class='list']/div[@class='property']/a//h3/text()")	

print(res)	#输出的是列表
fp=open("test.txt",mode="w+",encoding="utf-8")
for i in res:
    fp.write(i+'\n')
    fp.write('\n')
fp.close()


#我自己的代码
import requests
from lxml import etree
if __name__=="__main__":
    headers={
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'
    }
    url='https://zz.58.com/ershoufang/'
    page_text=requests.get(url=url,headers=headers).text
    #print(page_text)

    #数据解析
    tree=etree.HTML(page_text)

    #r1与r相同         #r1=tree.xpath('//section[@class="list"]/div/a/div[@class="property-content"]/div[@class="property-content-detail"]/div[@class="property-content-title"]/h3/text()')
    r = tree.xpath('//div[@class="property-content-title"]/h3/text()')

    print(r)
  

7、4K图片下载
单页图片
#需求:解析下载图片数据 http://pic.netbian.com/4kmeinv/
import requests
from lxml import etree
import os

if __name__=="__main__":
    #创建一个新文件夹
    if not os.path.exists('tupian'):
        os.mkdir('tupian')

    headers={
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'
    }
    url='https://pic.netbian.com/4kmeinv/'
    #先获取网页的HTML
    #page=requests.get(url=url,headers=headers).text        #乱码了
    respone=requests.get(url=url,headers=headers)
    #手动设定解决乱码
    #respone.encoding="utf-8"        #乱码没解决
    page=respone.text

    #数据解析
    tree=etree.HTML(page)
    li_list=tree.xpath('//div[@class="slist"]/ul/li')
    #print(li_list)
    for li in li_list:
        #图片的网址
        img_src='https://pic.netbian.com'+li.xpath('./a/img/@src')[0]
        #print(img_src)
        
        #图片名字
        img_name=li.xpath('./a/img/@alt')[0]+'.jpg'
        # 通用处理中文乱码的解决方案
        img_name=img_name.encode('iso-8859-1').decode('gbk')
        #print(img_name)

        #进行持久化存储
        img_data=requests.get(url=img_src,headers=headers).content #二进制数据
        #图片路径
        img_path='tupian/'+img_name
        with open(img_path,'wb') as fp:
            fp.write(img_data)
            print(img_name,'下载成功!!!')
        # with open(img_path,'wb') as fp:
        #     fp.write(img_data)
        #     print(img_name,"下载成功!!")




关于更多图片(dddd)
import os
import requests
from lxml import etree

header = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.5211 SLBChan/25"
}

picture_loc = []  # 图片存地址
picture_name_list = []  # 存图片名
# 第2,3页图片,可自行调节
# 不能包括1,因为1页面网址和后面网址不一样,如想包括,可添加if条件判断
for i in range(2, 4):
    # 一定要在循环内,否则一直为"https://pic.netbian.com/4kmeinv/index_2.html"
    # 关于为什么后面是/4kmeinv/index_{0}.html 代码后讲解
    url = "https://pic.netbian.com/4kmeinv/index_{0}.html"
    url = url.format(i)
    girl_data = requests.get(url=url, headers=header).text
    girl_data = girl_data.encode("iso-8859-1").decode('gbk')
    girl_etree = etree.HTML(girl_data, )
    # 地址压入
    picture_loc.extend(girl_etree.xpath("//ul[@class='clearfix']/li/a/img/@src"))
    # 图片名压入
    picture_name_list.extend(girl_etree.xpath("//ul[@class='clearfix']/li/a/b/text()"))

if not os.path.exists("you_knew_about_picture"):
    os.mkdir("./you_knew_about_picture")

a = 0  # 记录图片个数
for i, each_loc in enumerate(picture_loc):
    new_loc = "https://pic.netbian.com/" + each_loc

    each_picture_data = requests.get(new_loc, headers=header).content

    each_picture_name = "you_knew_about_picture/" + str(a) + " . " + picture_name_list[i] + ".jpg"

    fp = open(each_picture_name, mode="wb")
    fp.write(each_picture_data)
    fp.close()

    print(each_picture_name.split("/")[-1] + " have been over")
    a = a + 1
print(a)

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门