使用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)
print(soup.li.parent)
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'}) |
-- | 常用属性不用attrs | soup.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() | 返回节点前第一个符合条件的节点 |
方法 | 样例 | 说明 |
---|
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)