Python爬虫初级(八)—— lxml 详解及代理IP爬取

欢迎关注公众号K的笔记阅读博主更多优质学习内容
K的笔记公众号

上一篇内容:Python爬虫初级(七)—— 丁香园评论留言板爬取
前一篇文章的末尾我们提到,可以使用 lxml + xpath 提取文章内容,在这篇文章中,我们将对 lxml 与 xpath 进行详细阐述,在这之前我们使用 pip install lxml 安装 lxml 库。

Xpath 语法

XPath 即为 XML 路径语言(XML Path Language),它是一种用来确定 XML 文档中某部分位置的语言。而 XML 我们在这篇文章中已经提到了,它的语法与 HTML 基本一致,可以说是通过 HTML发展而来的通用表达形式。

路径表达式

XPath 使用路径表达式在 XML 文档中选取节点,节点是通过沿着路径选取的。下面列出了最常用的路径表达式:

表达式描述
nodename选取此节点的所有节点
/从根节点选取
//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
.选取当前节点
选取当前节点的父节点
@选取属性

Predicates

表达式描述实例解释
[n]选择某节点的第n(n>=1)个子节点xpath(“//h//a[1]”)选择h节点下第1个a节点
[last()]选择某节点的最后一个子节点xpath(“//h//a[last()]”)选择h节点下最后一个a节点
[@attribute]选择节点带有attribute属性的节点xpath(“//img[@src]”)选择带有src属性的img节点
[@attribute=value]选择带有attribute属性值的节点xpath(“//a[@href=”aaa.jpg”]”)选择href属性值为aaa.jpg的a节点
*任意匹配元素或者属性xpath(“//a/“),xpath(“//a[@]”)选择a节点下的所有子节点,选择带有属性的a节点

模糊搜索与匹配

函数用法解释
starts-withxpath(“//div[starts-with(@id,’user’)]”)选择id值以user开头的div节点
containsxpath(“//div[contains(@id,’user’)]”)选择id值包含user的div节点
andxpath(“//div[starts-with(@class,”login”) and contains(@id,’user’)]”)选择class值以login开头和id值包括user的div节点
text()xpath(“//div[starts-with(text(),”mytest”)]”)选取节点文本包含myest的div节点

xpath轴

轴名称表达式描述
ancestorxpath(“./ancestor:: *”)选取当前节点的所有父辈节点
ancestor-or.selfxpath(“./ancestor-or-self:: *”)选取当前节点的父辈节点和节点自身
childxpath(“./child:: *”)选择当前节点的所有子节点
descendantxpath(“./descendant:: *”)选择当前节点的所有后代节点(子节点、孙节点等)
followxpath(“./following:: *”)选取当前节点结束标签后的所有节点
follow-siblingxpath(“./follow-sibling:: *”)选取当前节点之后的兄弟节点
precedingxpath(“./preceding:: *”)选取当前开始标签前的所有节点

lxml 使用

首先需要导入库:from lxml import etree,下面这行代码 lxml 会将 html 文本转成 xml 对象

tree = etree.HTML(html)

我们要使用 lxml + Xpath 从源代码直接获取信息时,会使用 tree.xpath() 语句,括号内的是所需获取内容的一些形式,具体形式在上面已经列出了,比如我们要获取丁香园页面的用户名称信息,首先查看该页面源代码:
用户信息我们可以使用:

tree.xpath('//div[@class=“auth”]/a/text()')

我们想要获取评论信息:
评论信息
我们可以使用

tree.xpath('//td[@class=“postbody”]') 

我们需要注意的是,当我们将文本对象转换为了 lxml 对象后,实际获取内容的方式也发生了改变,参看下面代码:

from lxml import etree
text = '''
<div>
    <ul>
         <li class="item-0"><a href="link1.html">first item</a></li>
         <li class="item-1"><a href="link2.html">second item</a></li>
         <li class="item-inactive"><a href="link3.html">third item</a></li>
         <li class="item-1"><a href="link4.html">fourth item</a></li>
         <li class="item-0"><a href="link5.html">fifth item</a>
     </ul>
 </div>
'''
html = etree.HTML(text)
# 返回 <Element html at 0x233468e5788>
result = etree.tostring(html)
print(result)
# 返回 text 中信息

代理 IP 爬取

介绍完 xpath 的基本内容,我们下面来实战一个非常有用的爬虫 —— 爬取代理IP,其具体页面内容如下:
西刺代理IP主页
我们点击查看源代码,可以发现相关的IP地址直接出现在页面中,因此我们能够通过现有知识进行爬取:

西刺代理IP主页源代码
下面是测试代码:

>>> from lxml import etree
>>> import requests
>>> url = "https://www.xicidaili.com/"
>>> headers = {"user-agent":"Mozilla/5.0"}
>>> res = requests.get(url, headers=headers)
>>> res.status_code
200
>>> res.encoding = res.apparent_encoding
>>> text = res.text
>>> html = etree.HTML(text)
>>> html.xpath('/html/body/div[1]/div[2]/div[1]/div[1]/table/tbody/tr[3]/td[2]')
[]
>>> ip_ = html.xpath('/html/body/div[1]/div[2]/div[1]/div[1]/table//tr[3]/td[2]')
[<Element td at 0x233473b8d08>]
>>> result = etree.tostring(ip_[0])
>>> result
b'<td>119.4.13.26</td>\n 

事实上,我们在实际使用时,想要获得 Xpath 不一定会直接一行行代码看过去,更可能直接复制 Xpath:

查看器获取 Xpath
我们右键移至复制,会出现一个名为“复制Xpath”的选项,点击复制Xpath 后即可得到相应的 Xpath,但在这里有一点需要注意的是,Xpath 会给页面 HTML 树进行自动补齐,也就是说会出现一些原来没有的东西,就会出现上面代码中倒数第六行出现空返回的问题,这时候就需要我们去仔细检查哪里的信息可能是多余的。

下面我们展示完整代码:

import pickle#我们封装数据要用到的库
import requests
from lxml import etree

#请求头
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36',
}

def construct_url():#老样子,先构建url列表,我这就爬一页
    urls = []
    for i in range (1,2):
        url = 'https://www.xicidaili.com/nn/'+str(i)
        urls.append(url)
    return urls

def get_proxy(url):#从数据中解析出ip数据,并验证ip是否可用
    res = requests.get(url,headers=headers)
    html = etree.HTML(res.text,etree.HTMLParser())
    #把返回的数据解析成etree._Element对象,这样才可以使用Xpath语句提取数据
    ip = html.xpath('//*[@id="ip_list"]/tr/td[2]/text()')#ip
    ip_port = html.xpath('//*[@id="ip_list"]/tr/td[3]/text()')#端口号
    ip_type = html.xpath('//*[@id="ip_list"]/tr/td[6]/text()')#网络类型

    lis = []
    for i,j,k in zip(ip,ip_port,ip_type):
        try:
            proxies = {
                    k.lower():i+':'+j#注意到爬下来的是HTTP或者是HTTPS,我们要将它们变成http或https
                    }
            print(proxies)#把IP输出来看看
            requests.get('https://www.baidu.com/',headers=headers,timeout=1,proxies=proxies)
            #用这个IP发一个请求给百度,测试一下这个IP能不能用
            lis.append(proxies)#如果没有超时,说明能用,存进列表里
            print('http://'+i+':'+j+" is fine")
        except:
            print('http://'+i+':'+j+" is timeout")#超时抛出错误,输出哪个IP超时
    return lis#返回可用IP列表

if __name__=='__main__':
    urls = construct_url()
    lis = []
    for url in urls:
        rlist = get_proxy(url)
        lis += rlist
    pickle.dump(lis,open('ip.pkl','wb'))#将可用的IP进行存储
    
    print('----可用IP---')
    for item in lis:
        print(item)
    print('---  END  ---')
# 代码直接来源:https://blog.csdn.net/weixin_41169182/article/details/88676729

下一篇内容:Python爬虫初级(九)—— ajax 详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值