4. 解析库的使用

使用XPath

  • XPath常用规则
表达式描述
nodename选取此节点的所有子节点
/从当前节点选取直接子节点
//从当前节点选取子孙节点
.选取当前节点
..选取当前节点的父节点
@选取属性
  • lxml.etree(htmlText) 构造一个XPath解析对象,自动修正HTML,比如自动补足缺失的HTML标签
表达式描述
//*选择所有节点
//li选择所有li节点
//li/a选择li节点的所有直接a子节点
parent::获取父节点
//li[@class="item-0"]获取属性class为item-0的li节点
//li[@class="item-0"]/a/text()获得属性class为item-0的li节点的直接a子节点中的文本
//li/a/@href获得li节点下a子节点的href属性值
//li[contains(@class,'abc')]获得class属性包括abc的li节点
ancestor::获取所有祖先节点
attribute::获得所有属性值
child::获得所有直接子节点
descendant::获得所有子孙节点
fllowing::获得当前节点之后的所有节点
fllowing-sibling::获取当前节点之后的所有同级节点

使用 Beautiful Soup

  • Beautiful Soup 就是 Python 的一个HTML或XML的解析库,可以用它方便的从网络中提取数据
  • soup = BeautifulSoup(htmlText,'lxml') 构造lxml HTML 解析器
  • soup = BeautifulSoup(htmlText,'xml') 构造xml HTML 解析器
from bs4 import BeautifulSoup
soup = BeautifulSoup(html,'lxml')
  • soup.prettify() 把要解析的字符串以标准的缩进格式输出
  • soup.a 选择元素选择a标签节点,但是只返回第一个匹配的节点,如head、title都是唯一的
  • soup.li.attrs 获得标签的属性 soup.li.attrs['class'] 也可以指定属性名
  • soup.li['class'] 也可以直接获得标签的指定属性
  • soup.li.string 获取节点元素包含的文本内容
  • print(soup.ul.li.a['href']) 嵌套选择
  • 选择节点元素之后,如果想要获取它的节点,可以调用contents属性
print(soup.ul.children)
for i,child in enumerate(soup.ul.children):
    print(i,child)
  • 如果想要得到所有子孙节点的话,可以调用descendants属性
print(soup.ul.children)
for i,child in enumerate(soup.ul.descendants):
    print(i,child)
  • 选择父节点,用parent属性
print(soup.li.parent)
  • 选择所有的祖先节点,用parents属性
print(list(enumerate(soup.a.parents)))
  • 兄弟节点
属性内容
descendants获得所有子孙节点
parent选择父节点
parents选择所有的祖先节点
next_sibling下一个兄弟元素
previous_silbing上一个兄弟元素
next_siblings后面所有的兄弟节点
previous_siblings前面所有的兄弟节点
  • 方法选择器
  • find_all(name,attrs,recursive,text,*kwargs)
  • 返回所有匹配元素组成的列表
属性内容示例
name根据节点名查元素soup.ul.find_all(name='li')
attrs根据属性查询soup.find_all(attrs={'class':'item-0'})
--常用属性不用attrssoup.find_all(src='myimage.bmp')
--class是保留关键字加_soup.find_all(class_='item-0')
text可以用来匹配节点的文本soup.find_all(text='first item')
--不匹配标签或属性,可以是正则表达式soup.find_all(text=re.compile('item'))
  • 查询方法
方法内容
find_all()返回所有匹配元素组成的列表
find()返回第一个匹配的节点元素
find_parents()返回所有祖先节点
find_parent()返回直接父节点
find_next_siblings()返回后面所有的兄弟节点
find_next_sibling()返回后面第一个兄弟节点
find_previous_siblings()返回前面所有的兄弟节点
find_previous_sibling()返回前面第一个兄弟节点
find_all_next()返回节点后所有符合条件的节点
find_next()返回节点后第一个符合条件的节点
find_all_previous()返回节点前所有符合条件的节点
find_previous()返回节点前第一个符合条件的节点
  • CSS选择器
方法样例说明
select()soup.select('ul li')返回ul的所有li节点
---soup.select('#list-2 .element')返回id为list-2节点下的所有子节点
---soup.select('.item00 .item-0')有层级关系的class名字搜索,返回class='item-0'的节点
属性for item in soup.select('.item-0')item.img['alt'] 获得item子节点img的alt属性值

使用 pyquery

from pyquery import PyQuery as pq
import requests,json,re,time

class LazyMan():
    _myResult = []
    _pnglist1 = []
    _pnglist2 = []
    _pngFileRealList = []
    def get_one_page(self,inUrl):
        headers={
            'User-Agent': 'Mozilla/5.0(Macintosh;Intel Mac OS X 10_11_4) '
                          'AppleWebKit/537.36(KHTML,like Gecko) Chrome/52.0.2743.116 Safari/537.36'
        }
        response = requests.get(inUrl,headers=headers)
        if(response.status_code == 200):
            return response.text
        return None

    def urlListLayer1(self,inUrl):
        contents = self.get_one_page(inUrl)
        doc = pq(contents, parser='html')
        result = doc('.list-pngjs dl dd a')
        for item in result.items():
            theurl = "http://www.lanrentuku.com" + item.attr.href
            print(theurl)
            self._pnglist1.append(theurl)

    def write_to_file(self,inFileName,inNum):
        with open(inFileName,'a',encoding='utf-8') as f:
            if(inNum ==1):
                for item in self._pnglist1:
                    f.write(item+'\n')
            elif(inNum ==2):
                for item in self._pnglist2:
                    f.write(item+'\n')
        f.close()

    def read_from_file(self,inFileName):
        with open(inFileName,'r',encoding='utf-8') as f:
            for line in f.readlines():
                self._pnglist1.append(line.strip())
        f.close()

    def urlListLayer2(self, inUrl):
        self._pnglist2.append(inUrl)
        contents = self.get_one_page(inUrl)
        doc = pq(contents, parser='html')
        result = doc('.thisclass').siblings().find('a')
        #print(result)
        i = 1
        for item in result.items():
            if (i < len(result)):
                theurl = "http://www.lanrentuku.com" + item.attr.href
                i += 1
                self._pnglist2.append(theurl)
        for item in self._pnglist2:
            print(item)

    def getURL1(self,inNum):
        if(inNum ==1):
            return self._pnglist1
        elif(inNum ==2):
            return self._pngFileRealList
    #删除特殊字符
    def delSpeText(self,inText):
        removeExtraTag = re.compile('[\\|\/|\#|\?|\+|\*]')
        inText = re.sub(removeExtraTag, '', inText)
        # strip()将前后多于内容删除
        return inText.strip()

    #找出和记录图片名称与地址
    def urlRealPNGAdd(self,inUrl):
        contents = aLazy.get_one_page(inUrl)
        doc = pq(contents, parser='html')
        picTitle = doc('.title').find('h1').text()
        picTitle = self.delSpeText(picTitle.strip())
        imgTags = doc('.content-png').find('img')
        for item in imgTags.items():
            pngAddress = item.attr.src
            pngFileName = picTitle + pngAddress[len(pngAddress) - 8:]
            print(pngFileName , pngAddress)
            temp = [pngFileName, pngAddress]
            self._pngFileRealList.append(temp)

    #读出图片地址及title的json文件到数组
    def readJsonFile(self,inFile):
        with open(inFile, "r", encoding='utf-8') as f:
            self._pngFileRealList = json.load(f)

    def savePNGFile(self,imgURL,imgName):
        aFolderName = "png/"
        imgName = self.delSpeText(imgName)
        fileName = aFolderName + imgName
        headers = {
            'User-Agent': 'Mozilla/5.0(Macintosh;Intel Mac OS X 10_11_4) '
                          'AppleWebKit/537.36(KHTML,like Gecko) Chrome/52.0.2743.116 Safari/537.36'
        }
        response = requests.get(imgURL, headers=headers)
        with open(fileName, 'wb') as f:
            f.write(response.content)
        f.close()

# 输出
if __name__ == '__main__':
    aLazy = LazyMan()
    '''
    for page in range(1,87):
        url = "http://www.lanrentuku.com/png/p"+str(page)+".html"
        aLazy.urlListLayer1(url)
    #把第一层需要访问的地址列表写到01FirstLayerURL.txt中
    aLazy.write_to_file("01FirstLayerURL.txt",1)
    
    aLazy.read_from_file("01FirstLayerURL.txt")
    for item in aLazy.getURL1(1):
        aLazy.urlListLayer2(item)
    # 把第二层要访问的地址列表写到02SecondLayerURL.txt中
    aLazy.write_to_file("02SecondLayerURL.txt",2)
    '''

    '''
    # 组织二维数组写入和读取txt,转用json格式
    data = [
        ["水果123.jpg","abc123.jpg"],
        ["水果124.jpg","abc124.jpg"],
        ["水果125.jpg","abc125.jpg"]
    ]
    the_data = {}
    with open("png.txt","w",encoding='utf-8') as f:
        f.write(json.dumps(data,indent=4,ensure_ascii=False))
    with open("png.txt","r",encoding='utf-8') as f:
        the_data = json.load(f)
    print(the_data)
    for items in the_data:
        print(items[0],items[1])
    '''
    '''
    # 搜寻所有PNG图片真实地址,并结合title名称,转为JSON写入03PNGAddress.txt
    aLazy.read_from_file("02SecondLayerURL.txt")
    for item in aLazy.getURL1(1):
        aLazy.urlRealPNGAdd(item)

    with open("03PNGAddress.txt", "w", encoding='utf-8') as f:
        f.write(json.dumps(aLazy.getURL1(2), indent=4, ensure_ascii=False))
    '''
    aLazy.readJsonFile("03PNGAddress.txt")
    i=1
    for item in aLazy.getURL1(2):
        i+=1
        print(item[0],item[1])
        aLazy.savePNGFile(item[1],item[0])
        if(i%100 == 0):
            print("Sleeping...")
            time.sleep(1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值