python学习——xpath

回顾

  • 5种反爬机制

    • robots.txt:反爬机制,防君子不防小人
    • UA检测:UA伪装
    • 数据加密
    • 图片懒加载
    • 代理ip
  • requests模块爬取流程:
    • 指定url
    • 发起请求
    • 获取页面数据
    • 数据解析
    • 持久化存储
  • bs4解析:
    • 环境安装:bs4、lxml解析器
    • 实例化bs对象,将页面源码数据加载到该对象中
    • 定位标签
      • find(‘a‘,class_=‘xxx‘)
      • findall()
      • select()
        • 大于号,一个层级
        • 空格,多个层级
    • 将标签中的文本内容获取
      • string 返回标签下文本内容
      • text 返回标签下所有字标签问本内容
      • get_text()
      • 获取属性
        • a[‘href‘]

xpath使用(【重点】xpath表达式)

  • 环境安装:pip install lxml
  • 解析原理:
    • 获取页面源码数据
    • 实例化一个etree的对象,并且将页码源数据加载到该对象中
    • 调用该对象的xpath方法进行制定标签的定位
    • 【注意】xpath函数必须结合着xpath表达式进行标签定位和内容捕获
  • 将html文档或xml文档转换成一个etree对象,然后调用对象中的方法查找指定的节点
    • 本地文件:tree = etree.parse(文件名)

         tree.xpath(‘xpath表达式‘)
    • 网络数据:tree = etree.HTML(网页内容字符串)
         tree.xpath(‘xpath表达式‘)

xpath表达式

  • / 层级之间的关系

    • / 相当于bs4中select中的>
    • // 相当于bs4-select中的空格
  • 举例:
    • /html/head/title 从根目录开始找,html下的 head标签下的 title标签
    • //head/title 先找到当前源码中所有的head标签,在找到head标签下的title标签
    • //title 找到所有title标签
    • 属性定位:
      • //div[@class=‘song‘] 定位所有class属性值为song的div标签;[]中必须跟@符号,属性名称前必须有@【语法结构】,返回的是列表
    • 层级&索引定位:
      • //div[@class=‘tang‘]/ul/li[2]/a 定位所有class属性值为tong的div直系标签 ul标签下的 第二个li标签下的直系字标签 a标签;
    • 逻辑运算:
      • //a[@href=‘‘ and @class=‘du‘] 定位所有href属性值为空且class属性值为du的所有a标签
    • 模糊匹配:
      • //div[contain(@class,‘ng‘)] 定位class属性值包含ng的所有div标签
      • //div[start-with(@class,‘ta)] 定位class属性值以ta开头的所有div标签
    • 取文本
      • 表示获取某个标签下的文本内容
      • 表示获取某个标签下的文本内容和所有子标签下的文本内容
      • //div[@class=‘song‘]/p[1]/text() 获取class属性值为song的所有div标签下的 第一个p字标签 包含的文本
      • //div[@class=‘tang]//text() 获取class属性值为tang的所有div标签下的 所有文本,及其字标签下的所有文本,返回的是列表,列表里有多个列表元素
    • 取属性
      • //div[@class=‘tang‘]//li[2]/a/@href 返回属性对应的属性值

案例:获取58二手房相关房源信息

In [1]:

import requests
from lxml import etree

url = ‘https://bj.58.com/beijingzhoubian/ershoufang/?PGTID=0d30000c-0000-1175-8e33-a6e941f8aff5&ClickID=1‘
headers = {
    ‘User-Agent‘:‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER‘
}
# 获取源码数据
page_text = requests.get(url=url,headers=headers).text
# 实例化etree对象
tree = etree.HTML(page_text)
# 调用xpath方法,后去li标签列表
li_list = tree.xpath(‘//ul[@class="house-list-wrap"]/li‘)
fp = open(‘58.csv‘,‘w‘,encoding=‘utf-8‘)
#遍历列表
for li in li_list:
    # .开头的意思:进行局部页面解析;./开头表示从li标签开始解析
    title = li.xpath(‘./div[2]/h2/a/text()‘)[0]
    price = li.xpath(‘./div[3]//text()‘)
    #将价格的三个列表拼接为字符串
    price = ‘‘.join(price)
    fp.write(title+‘:‘+price+‘\n‘)
fp.close()
print(‘over‘)
over

案例:获取图片

In [27]:

import requests
from lxml import etree
import os
import urllib

url = ‘http://pic.netbian.com/4kmeinv/‘
headers = {
    ‘User-Agent‘:‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER‘
}
response = requests.get(url=url,headers=headers)
#response.encoding = ‘utf-8‘
if not os.path.exists(‘./imgs‘):
    os.mkdir(‘./imgs‘)
page_text = response.text

tree = etree.HTML(page_text)
li_list = tree.xpath(‘//dic[@class="slist"]/ul/li‘) # //dic[@class="slist"]//li
for li in li_list:
    img_name = li.xpath(‘./a/b/text()‘)[0]
    # 处理中文乱码
    img_name = img_name.encode(‘iso-8859-1‘).decode(‘gbk‘)
    img_url = ‘http://pic.netbian.com‘ + li.xpath(‘./a/img/@src‘)[0]
    img_path = ‘./imgs/‘ + img_name + ‘.jpg‘
    urllib.request.urlretrieve(url=img_url,filename=img_path)
    print(img_path,‘下载成功‘)

案例:煎蛋网中图片数据:http://jandan.net/ooxx

  • 第三种反爬机制:数据加密

In [6]:

import requests
from lxml import etree
import base64
import urllib

headers = {
    ‘User-Agent‘:‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER‘
}
url = ‘http://jandan.net/ooxx‘
page_text = requests.get(url=url,headers=headers).text

tree = etree.HTML(page_text)
img_hash_list = tree.xpath(‘//span[@class="img-hash"]/text()‘)
for img_hash in img_hash_list:
    img_url = ‘http:‘ + base64.b64decode(img_hash).decode()
    img_name = img_url.split(‘/‘)[-1]
    urllib.request.urlretrieve(url=img_url,filename=img_name)

爬取站长素材中的简历模板

In [12]:

import requests
from lxml import etree
import random

headers = {
    ‘Connection‘:‘close‘,# 当请求成功后,马上断开该次请求(及时释放请求池中的资源))
    ‘User-Agent‘:‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER‘
}
url = ‘http://sc.chinaz.com/jianli/free-%d.html‘
for page in range(1,4):
    if page == 1:
        new_url = ‘http://sc.chinaz.com/jianli/free.html‘
    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)
    div_list = tree.xpath(‘//div[@id="container"]/div‘)
    for div in div_list:
        detail_url = div.xpath(‘./a/@href‘)[0]
        name = div.xpath(‘./a/img/@alt‘)[0]

        detail_page = requests.get(url=detail_url,headers=headers).text
        tree = etree.HTML(detail_page)
        download_list = tree.xpath(‘//div[@class="clearfix mt20 downlist"]/ul/li/a/@href‘)
        download_url = random.choice(download_list)
        data = requests.get(url=download_url,headers=headers).content
        file_name = name + ‘.rar‘
        with open(file_name,‘wb‘) as fp:
            fp.write(data)
            print(file_name,‘下载成功‘)
机械电子工程师简历模板.rar 下载成功
设计师英文简历模板下载.rar 下载成功
化妆师个人简历范文.rar 下载成功
---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
E:\Anaconda3\lib\socket.py in readinto(self, b)
    588             try:
--> 589                 return self._sock.recv_into(b)
    590             except timeout:

OSError: [WinError 10051] 向一个无法连接的网络尝试了一个套接字操作。

During handling of the above exception, another exception occurred:

KeyboardInterrupt                         Traceback (most recent call last)
<ipython-input-12-e1e8f04f99ec> in <module>
     26         download_list = tree.xpath(‘//div[@class="clearfix mt20 downlist"]/ul/li/a/@href‘)
     27         download_url = random.choice(download_list)
---> 28         data = requests.get(url=download_url,headers=headers).content
     29         file_name = name + ‘.rar‘
     30         with open(file_name,‘wb‘) as fp:

E:\Anaconda3\lib\site-packages\requests\api.py in get(url, params, **kwargs)
     73
     74     kwargs.setdefault(‘allow_redirects‘, True)
---> 75     return request(‘get‘, url, params=params, **kwargs)
     76
     77 

E:\Anaconda3\lib\site-packages\requests\api.py in request(method, url, **kwargs)
     58     # cases, and look like a memory leak in others.
     59     with sessions.Session() as session:
---> 60         return session.request(method=method, url=url, **kwargs)
     61
     62 

E:\Anaconda3\lib\site-packages\requests\sessions.py in request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
    531         }
    532         send_kwargs.update(settings)
--> 533         resp = self.send(prep, **send_kwargs)
    534
    535         return resp

E:\Anaconda3\lib\site-packages\requests\sessions.py in send(self, request, **kwargs)
    684
    685         if not stream:
--> 686             r.content
    687
    688         return r

E:\Anaconda3\lib\site-packages\requests\models.py in content(self)
    826                 self._content = None
    827             else:
--> 828                 self._content = b‘‘.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b‘‘
    829
    830         self._content_consumed = True

E:\Anaconda3\lib\site-packages\requests\models.py in generate()
    748             if hasattr(self.raw, ‘stream‘):
    749                 try:
--> 750                     for chunk in self.raw.stream(chunk_size, decode_content=True):
    751                         yield chunk
    752                 except ProtocolError as e:

E:\Anaconda3\lib\site-packages\urllib3\response.py in stream(self, amt, decode_content)
    492         else:
    493             while not is_fp_closed(self._fp):
--> 494                 data = self.read(amt=amt, decode_content=decode_content)
    495
    496                 if data:

E:\Anaconda3\lib\site-packages\urllib3\response.py in read(self, amt, decode_content, cache_content)
    440             else:
    441                 cache_content = False
--> 442                 data = self._fp.read(amt)
    443                 if amt != 0 and not data:  # Platform-specific: Buggy versions of Python.
    444                     # Close the connection when no data is returned

E:\Anaconda3\lib\http\client.py in read(self, amt)
    445             # Amount is given, implement using readinto
    446             b = bytearray(amt)
--> 447             n = self.readinto(b)
    448             return memoryview(b)[:n].tobytes()
    449         else:

E:\Anaconda3\lib\http\client.py in readinto(self, b)
    489         # connection, and the user is reading more bytes than will be provided
    490         # (for example, reading in 1k chunks)
--> 491         n = self.fp.readinto(b)
    492         if not n and b:
    493             # Ideally, we would raise IncompleteRead if the content-length

E:\Anaconda3\lib\socket.py in readinto(self, b)
    587         while True:
    588             try:
--> 589                 return self._sock.recv_into(b)
    590             except timeout:
    591                 self._timeout_occurred = True

KeyboardInterrupt: 

【重点】

  • 问题:往往在进行大量请求发送的时候,经常会报出这样一个错误:HTTPConnectionPool(host:XX)Max retries exceeded with url.
  • 原因:
    • 1.每次数据传输前客户端要和服务器简历TCP连接,为节省传输消耗,默认为keep-alive,即连接一次,传输多次,然而如果连接迟迟不断开的话,连接池满后则无法产生新的连接对象,导致请求无法发送。
    • 2.ip被封
    • 3.请求频率太频繁
  • 解决:如果下列解决未生效,则可以尝试再次执行程序(因为第一次运行Connection可能不生效)
    • 1.设置请求头中的Connection的值为close,表示每次请求成功后断开连接
    • 2.更换请求ip(使用非常简单,之间直接在get/post请求中加个参数)
    • 3.每次请求之间使用sleep进行等待间隔【不推荐,影响效率】

解析所有城市名称 https://www.aqistudy.cn/historydata/

In [16]:

import requests
from lxml import etree
import random

headers = {
    ‘Connection‘:‘close‘,# 当请求成功后,马上断开该次请求(及时释放请求池中的资源))
    ‘User-Agent‘:‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER‘
}
url = ‘https://www.aqistudy.cn/historydata/‘
page_text = requests.get(url=url,headers=headers).text

tree = etree.HTML(page_text)
li_list = tree.xpath(‘//div[@class="bottom"]/ul/li | //div[@class="bottom"]/ul/div[2]/li‘)
for li in li_list:
    city_name = li.xpath(‘./a/text()‘)[0]
    print(city_name)
北京
上海
广州
深圳
杭州
天津
成都
南京
西安
武汉
阿坝州
安康
阿克苏地区
阿里地区
阿拉善盟
阿勒泰地区
安庆
安顺
鞍山
克孜勒苏州
安阳
蚌埠
白城
保定
北海
宝鸡
北京
毕节
博州
白山
百色
保山
白沙
包头
保亭
本溪
巴彦淖尔
白银
巴中
滨州
亳州
长春
昌都
常德
成都
承德
赤峰
昌吉州
五家渠
昌江
澄迈
重庆
长沙
常熟
楚雄州
朝阳
沧州
长治
常州
潮州
郴州
池州
崇左
滁州
定安
丹东
东方
东莞
德宏州
大理州
大连
大庆
大同
定西
大兴安岭地区
德阳
东营
黔南州
达州
德州
儋州
鄂尔多斯
恩施州
鄂州
防城港
佛山
抚顺
阜新
阜阳
富阳
抚州
福州
广安
贵港
桂林
果洛州
甘南州
固原
广元
贵阳
甘孜州
赣州
广州
淮安
海北州
鹤壁
淮北
河池
海东地区
邯郸
哈尔滨
合肥
鹤岗
黄冈
黑河
红河州
怀化
呼和浩特
海口
呼伦贝尔
葫芦岛
哈密地区
海门
海南州
淮南
黄南州
衡水
黄山
黄石
和田地区
海西州
河源
衡阳
汉中
杭州
菏泽
贺州
湖州
惠州
吉安
金昌
晋城
景德镇
金华
西双版纳州
九江
吉林
即墨
江门
荆门
佳木斯
济南
济宁
胶南
酒泉
句容
湘西州
金坛
鸡西
嘉兴
江阴
揭阳
济源
嘉峪关
胶州
焦作
锦州
晋中
荆州
库尔勒
开封
黔东南州
克拉玛依
昆明
喀什地区
昆山
临安
六安
来宾
聊城
临沧
娄底
乐东
廊坊
临汾
临高
漯河
丽江
吕梁
陇南
六盘水
拉萨
乐山
丽水
凉山州
陵水
莱芜
莱西
临夏州
溧阳
辽阳
辽源
临沂
龙岩
洛阳
连云港
莱州
兰州
林芝
柳州
泸州
马鞍山
牡丹江
茂名
眉山
绵阳
梅州
宁波
南昌
南充
宁德
内江
南京
怒江州
南宁
南平
那曲地区
南通
南阳
平度
平顶山
普洱
盘锦
蓬莱
平凉
莆田
萍乡
濮阳
攀枝花
青岛
琼海
秦皇岛
曲靖
齐齐哈尔
七台河
黔西南州
清远
庆阳
钦州
衢州
泉州
琼中
荣成
日喀则
乳山
日照
韶关
寿光
上海
绥化
石河子
石家庄
商洛
三明
三门峡
山南
遂宁
四平
商丘
宿迁
上饶
汕头
汕尾
绍兴
三亚
邵阳
沈阳
十堰
松原
双鸭山
深圳
朔州
宿州
随州
苏州
石嘴山
泰安
塔城地区
太仓
铜川
屯昌
通化
天津
铁岭
通辽
铜陵
吐鲁番地区
铜仁地区
唐山
天水
太原
台州
泰州
文昌
文登
潍坊
瓦房店
威海
乌海
芜湖
武汉
吴江
乌兰察布
乌鲁木齐
渭南
万宁
文山州
武威
无锡
温州
吴忠
梧州
五指山
西安
兴安盟
许昌
宣城
襄阳
孝感
迪庆州
锡林郭勒盟
厦门
西宁
咸宁
湘潭
邢台
新乡
咸阳
新余
信阳
忻州
徐州
雅安
延安
延边州
宜宾
盐城
宜昌
宜春
银川
运城
伊春
云浮
阳江
营口
榆林
玉林
伊犁哈萨克州
阳泉
玉树州
烟台
鹰潭
义乌
宜兴
玉溪
益阳
岳阳
扬州
永州
淄博
自贡
珠海
湛江
镇江
诸暨
张家港
张家界
张家口
周口
驻马店
章丘
肇庆
中山
舟山
昭通
中卫
张掖
招远
资阳
遵义
枣庄
漳州
郑州
株洲

反爬机制:图片懒加载

  • src属性下有两种图片地址:src/src2,当图片出现在可视化窗口中时出现src,为图片真正地址;当图片不在可视化范围中时图片url为src2;而src2为错误地址,所以当使用爬虫时,出现的是错误的src2地址,所以爬取不到图片。

设置请求的代理IP

  • 使用方法:

    • 直接在get/post请求中加入proxies={‘类型‘:‘ip‘}
    • 代理ip的类型必须和请求url的协议头保持一致
  • 提供代理ip的网站:
    • www.goubanjia.com
    • 快代理
    • 西祠代理
  • 每种代理ip分两种类型:http/https
  • 代理池 [dic1,dic2,dic3...] proxies=

In [24]:

import requests

url = ‘https://www.baidu.com/s?wd=ip‘

page_text = requests.get(url=url,headers=headers,proxies={‘https‘:‘36.111.140.6:8080‘}).text

with open(‘./ip.html‘,‘w‘,encoding=‘utf-8‘) as fp:
    fp.write(page_text)

原文地址:https://www.cnblogs.com/bilx/p/11553081.html

时间: 2024-10-09 23:18:00

python学习——xpath的相关文章

python学习(二)百度爬虫0.1

参照着网上的爬虫案例(点我),先做了一个demo,基本的爬虫项目创建,以及数据抽取,数据分析,数据保存等等过程基本上有所掌握. 我的需求是需要检索指定的百度贴吧,根据指定的关键字库,搜索出含有关键字的链接,并抽取出来,用于后续告警. 因此,基于需求,分如下步骤: 第一:基于Scrapy创建爬虫项目: 第二:新建TieBaSpider爬虫: 第三:新建外部关键字库dictionary.txt文件,贴吧地址配置url.txt文件: 第一步参考晚上案例. 从第二步开始,编写爬虫,同时创建实例对象以及创

Python学习--Selenium模块学习(2)

Selenium的基本操作 获取浏览器驱动寻找方式 1. 通过手动指定浏览器驱动路径2. 通过 `$PATH`环境变量找寻浏览器驱动 可参考Python学习--Selenium模块简单介绍(1) 控制浏览器访问URL browser.get(https://www.baidu.com/)   find系列函数定位元素 - `find_element_by_xxx` 返回第一个符合条件 `WebElement` - `find_elements_by_xxx` 返回符合条件所有元素包含了`WebE

2019最新Python学习教程(Python学习路线_Python爬虫教程)爬虫工程师必备的10个爬虫工具

2019最新Python学习教程(Python学习路线_Python爬虫教程)爬虫工程师必备的10个爬虫工具 爬虫工程师必备的10个爬虫工具! 最近很多学爬虫的伙伴让推荐顺手的爬虫工具,总结了一下,把这些好用的爬虫工具都跟你们找齐活了! 磨刀不误砍柴工!都知道工欲善其事必先利其器,那么作为经常要和各大网站做拉锯战的爬虫工程师们,更需要利用利用好身边的一切法器,才能更快的攻破对方防线.这里以日常爬虫流程,给大家介绍十款爬虫工具,相信大家掌握以后,工作效率提高是完全没有问题了! 大家也可以看看有你们

python学习:程序控制结构·作业20141219

Python学习:程序控制结构 20141219 编程环境: windows 7 x64 python 2.7.6 题目: 1 编写程序,完成下列题目(1分) 题目内容: 如果列出10以内自然数中3或5的倍数,则包括3,5,6,9.那么这些数字的和为23.要求计算得出任意正整数n以内中3或5的倍数的自然数之和. 输入格式: 一个正整数n. 输出格式: n以内中3或5的倍数的自然数之和. 输入样例: 10 输出样例: 23 时间限制:500ms内存限制:32000kb n = int(raw_in

python学习第二天

python学习的第二天就是个灾难啊,这天被打击了,自己写的作业被否认了,不说了,写博客还是个好习惯的,要坚持下去,就不知道能坚持到什么时候.呵呵!!! 这天教的知识和第一天的知识相差不大,区别在于比第一天讲的更细了(我们是两个老师教的,风格是不一样的),这次也写那些比较细的知识点. python的简介 (1)你的程序一定要有个主文件. (2)对于python,一切事物都是对象,对象基于类创建.#似懂非懂,不过有那么点似懂. 知识点 #__divmod__ 会把两个数字相除的商和余数以元组的方式

[Python 学习] 二、在Linux平台上使用Python

这一节,主要介绍在Linux平台上如何使用Python 1. Python安装. 现在大部分的发行版本都是自带Python的,所以可以不用安装.如果要安装的话,可以使用对应的系统安装指令. Fedora系统:先以root登入,运行 yum install python Ubuntu系统:在root组的用户, 运行 sudo apt-get install python 2. 使用的Python的脚本 Linux是一个以文件为单位的系统,那么我们使用的Python是哪一个文件呢? 这个可以通过指令

python学习之最简单的用户注册及登录验证小程序

文章都是从我的个人博客上粘贴过来的哦,更多内容请点击 http://www.iwangzheng.com 正如很多同学所知道的,楼主开始学习python了,前进的道路曲曲折折,有荆棘也有陷阱,从最简单的小程序写起,每天练习,将python进行到底. 有一点比较别扭的就是python的换行之后空四个空格,ruby都是两个,并且python在方法和循环语句的第一句都要加冒号 mysql> show create table user; mysql> alter table user add sal

python学习--创建模块

昨天做了python客户端和服务器端通信,并把接收到的信息写到数据库,因为对数据库进行操作是个经常调用的行为,所以我想把调用数据库的操作写成一个module来给其它python程序调用,所以将昨天的服务器端程序拆分为两个文件: 1.主程序python.py #!/usr/bin/env python import socket import json import connmysql s = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) h

OpenCV之Python学习笔记

OpenCV之Python学习笔记 直都在用Python+OpenCV做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书<OpenCV Computer Vision with Python>,于是就看一遍,顺便把自己掌握的东西整合一下,写成学习笔记了.更需要的朋友参考. 阅读须知: 本文不是纯粹的译文,只是比较贴近原文的笔记:         请设法购买到出版社出版的书,支持正版. 从书名就能看出来本书是介绍在Pytho