数据解析

Spider常用知识

二.数据解析

1.正则

贪婪匹配和惰性匹配

 .*     贪婪匹配,  尽可能多的去匹配结果
 .*?    惰性匹配,  尽可能少的去匹配结果 -> 回溯

这两个要着重的说一下. 因为我们写爬虫用的最多的就是这个惰性匹配.

re模块中我们只需要记住这么几个功能就足够我们使用了.

  1. findall 查找所有. 返回list

    lst = re.findall("m", "mai le fo len, mai ni mei!") 
    print(lst)    # ['m', 'm', 'm'] 
    lst = re.findall(r"\d+", "5点之前. 你要给我5000万")
    print(lst)   # ['5', '5000']
    
  2. search 会进行匹配. 但是如果匹配到了第一个结果. 就会返回这个结果. 如果匹配不上search返回的则是None

    ret = re.search(r'\d', '5点之前. 你要给我5000万').group()
    print(ret) # 5
    
  3. match 只能从字符串的开头进行匹配

    ret = re.match('a', 'abc').group()  
    print(ret)     # a
    
  4. finditer, 和findall差不多. 只不过这时返回的是迭代器(重点)

    it = re.finditer("m", "mai le fo len, mai ni mei!")
    
    for el in it:
        print(el.group()) # 依然需要分组
    
  5. compile() 可以将一个长长的正则进行预加载. 方便后面的使用

    obj = re.compile(r'\d{3}')  # 将正则表达式编译成为一个 正则表达式对象, 规则要匹配的是3个数字
    ret = obj.search('abc123eeee') # 正则表达式对象调用search, 参数为待匹配的字符串
    print(ret.group())  # 结果: 123
    
  6. 正则中的内容如何单独提取?

    单独获取到正则中的具体内容可以给分组起名字

    s = """
    <div class='西游记'><span id='10010'>中国联通</span></div>
    """
    obj = re.compile(r"<span id='(?P<id>\d+)'>(?P<name>\w+)</span>", re.S)
    
    result = obj.search(s)
    print(result.group())  # 结果: <span id='10010'>中国联通</span>
    print(result.group("id"))  # 结果: 10010 # 获取id组的内容
    print(result.group("name"))  # 结果: 中国联通 # 获取name组的内容
    

    这里可以看到我们可以通过使用分组. 来对正则匹配到的内容进一步的进行筛选.

案例(免费代理池抓取)

import requests
import re

url="http://www.66ip.cn/mo.php?sxb=&tqsl=50&port=&export=&ktip=&sxa=&submit=%CC%E1++%C8%A1&textarea="

headers={
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}
f=open("ips.csv",mode="a",encoding="utf-8")
for i in range(10):
    resp=requests.get(url,headers=headers)
    page_sourse=resp.text

    obj=re.compile(r"var mediav_ad_height = '60';.*?</script>(?P<ipss>.*?)</div>",re.S)

    result=obj.search(page_sourse)
    ips=result.group("ipss").strip().replace("\r","").replace("\n","").replace("\t","").split("<br />")[0:-1]
    for ip in ips:
        f.write(f"{ip}\n")
f.close()

2.bs4

bs4模块安装

pip install bs4 

语法:
find(标签, 属性=值)
意思是在页面中查找 xxx标签, 并且标签的xxx属性必须是xxx值
例:
find('div', age=18) 含义: 在页面中查找div标签, 并且属性age必须是18的这个标签.
find_all()的用法和find()几乎一致. find()查找1个. find_all()查找页面中所有的.

<div class="honor">  

page.find("div", class="honor") 
注意, python中class是关键字. 会报错的. 怎么办呢? 可以在class后面加个下划线
page.find("div", class_="honor")

我们可以使用第二种写法来避免这类问题出现

page.find("div", attrs={"class": "honor"})

方法:

#提取文本
find().text
#提取属性
find().get("属性标签")

示例代码:

html = """
<ul>
    <li><a href="zhangwuji.com">张无忌</a></li>
    <li id="abc"><a href="zhouxingchi.com">周星驰</a></li>
    <li><a href="zhubajie.com">猪八戒</a></li>
    <li><a href="wuzetian.com">武则天</a></li>
</ul>
"""
from bs4 import BeautifulSoup

page = BeautifulSoup(html, "html.parser")
lis = page.find_all("li")
for li in lis:
    print(li.find("a").get("href"))

案例

import requests
from bs4 import BeautifulSoup

headers={
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}

url="https://movie.douban.com/top250"

resp=requests.get(url,headers=headers)
page=BeautifulSoup(resp.text)

lis=page.find_all("div",class_="info")
for li in lis:
    print(li.find_next("span",class_="title").text)
    print(li.find_next("div",class_="hd").find_next("a").get("href"))

3.xpath

安装lxml模块.

pip install lxml

用法:

  1. 将要解析的html内容构造出etree对象.
  2. 使用etree对象的xpath()方法配合xpath表达式来完成对数据的提取

案例

import requests
from lxml import etree

headers={
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
}

url="https://movie.douban.com/top250"

resp=requests.get(url,headers=headers)
#构造etree对象
tree=etree.HTML(resp.text)
lis=tree.xpath("//div[@class='item']")
with open("dbxpath.csv",mode='w',encoding='utf-8')as f:
    for li in lis:
        #提取文本
        name=li.xpath("./div[2]/div/a/span[1]/text()")[0]
        #提取属性
        href=li.xpath("./div/a/@href")[0]
        f.write(f"{name},{href}\n")
posted @ 2024-03-31 21:49  cker  阅读(25)  评论(0)    收藏  举报