聚焦爬虫之正则解析

一、聚焦爬虫:

  如果想要爬取页面中指定的内容,就要用到聚焦爬虫, 必须建立在通用爬虫的基础上

二、聚焦爬虫的编码流程:

  指定URL

  发送请求

  获取响应数据

  数据解析

  持久化存储

如何实现数据解析:

  正则解析(1个案例)

  bs4(BeautifulSoup4)解析(1个案例)

  xpath解析(通用性比较强, 3个案例)

数据解析的原理:

  进行标签的定位

  通过定位到的标签进行取文本和取属性

五、代码实现——正则解析

1、如何用爬虫程序下载一张图片

# 如何用爬虫程序下载一张图片
import requests

img_url = "http://www.521609.com/uploads/allimg/140717/1-140GF92503-lp.jpg"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
}

response = requests.get(url=img_url, headers=headers)

img_data = response.content  # 如果下载的是图片,视频或其他文件的数据,统一都为二进制数据,需要用到response.content来获取

with open("./meinv.jpg", 'wb') as f:
    f.write(img_data)

2、使用urllib模块下载图片(代码非常简洁)

# 使用urllib模块下载图片(代码非常简洁)
# 有一个缺陷,就是没有实现UA伪装,如果遇到有UA检测的网站的话,还是得换回requests模块
from urllib import request

url = "http://www.521609.com/uploads/allimg/140717/1-140GF92626-lp.jpg"

request.urlretrieve(url=url, filename="./qingmeizi.jpg")

3、爬取并下载校花网里面美女校花版块里面的图片

# 案例: 爬取并下载校花网里面美女校花版块里面的图片
import re
import os
import requests
from urllib import request

# 1. 指定URL
url = "http://www.521609.com/meinvxiaohua/"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
}
ex = '<li><a href=.*?<img src="(.*?)" width="160" height="220".*?</a></li>'

# 创建一个存放图片的目录
if not os.path.exists('./meinv'):
    os.mkdir('./meinv')

# 2. 发送请求
response = requests.get(url=url, headers=headers)

# 3. 获取页面源码数据
page_text = response.text

# 4. 数据解析(先要去网页上去分析页面源码里面的标签)
url_list = re.findall(ex, page_text, re.S)
print(url_list)

# 5. 持久化存储
for url in url_list:
    img_url = "http://www.521609.com" + url
    img_name = url.split("/")[-1]
    img_path = "./meinv/" + img_name  # ./meinv/10642054117-1.jpg
    
    # 使用urllib模块下载图片
    request.urlretrieve(img_url, img_path)
    print("{img_name}图片下载完成".format(img_name=img_name))

注解:re.S:单行匹配

# re.S :单行匹配
import re

html = """<li><a href="/meinvxiaohua/1987.html"><img src="/uploads/allimg/090616/10642054117-1.jpg" width="160" height="220" border="0" alt="东莞理工学院城市学院2009"></a><br>
                <a href="/meinvxiaohua/1987.html" class="title">东莞理工学院城市学院2009</a></li>"""

ex = '<li><a href=.*?<img src="(.*?)" width="160" height="220".*?</a></li>'

url = re.findall(ex, html, re.S)[0]
print(url)

六、代码实现——bs4解析

bs4解析

  • bs4的安装

    • pip3 install bs4
    • pip3 install lxml
  • bs4的使用:

    • from bs4 import BeautifulSoup
  • bs4的解析原理:

      1. 实例化一个BeautifulSoup对象,将页面源码数据加载到该对象中
      1. 使用该对象中的相关方法,进行标签内的文本和属性的提取
  • bs4的使用方法:

    • 本地加载
      • f = open("./meinv.jpg", 'rb')
      • soup = BeautifulSoup(f, 'lxml') # 第一个参数是文件句柄
    • 网络加载
      • page_text = requests.get(url=url).text
      • soup = BeautifulSoup(page_text, 'lxml')
  • soup对象的相关方法: (1)根据标签名查找

      - soup.a   获取页面源码中第一个符合要求的标签

    (2)获取属性, 返回的永远是一个单数

      - soup.a.attrs  获取a所有的属性和属性值,返回一个字典
      - soup.a.attrs['href']   获取href属性
      - soup.a['href']   也可简写为这种形式

    (3)获取文本内容

      - soup.string: 只可以获取直系标签中的文本内容
      - soup.text: 获取标签下的所有文本内容
      - soup.get_text(): 获取标签下的所有文本内容
     【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容

    (4)find():找到第一个符合要求的标签, 返回的永远是一个单数

      - soup.find('a') 通过标签名进行数据解析
      通过标签属性进行数据解析:
      - soup.find('a', title="xxx")
      - soup.find('a', alt="xxx")
      - soup.find('a', class_="xxx")
      - soup.find('a', id="xxx")

    (5)find_all:找到所有符合要求的标签, 返回的永远是一个列表

      - soup.find_all('a')
      - soup.find_all(['a','b']) 找到所有的a和b标签
      - soup.find_all('a', limit=2)  限制前两个

    (6)根据选择器选择指定的内容

      select选择器, 返回的永远是一个列表: soup.select('#feng') 
      - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
      - 层级选择器:
          - 单层级: div > p > a > .lala          只能是下面一级
          - 多层级: div .tang a  下面好多级

    【注意】select选择器返回永远是列表,需要通过下标提取指定的对象

例如:

from bs4 import BeautifulSoup

# 1 读取本地文件的文件句柄
f = open('./test_page.html', 'r', encoding='utf-8')

# 2 实例化一个BeautifulSoup对象
soup = BeautifulSoup(f, 'lxml')
print(soup)

soup.a
soup.div
soup.a.attrs.get("title")
soup.a.get("href")

 七、代码实现——xpath解析

xpath解析

  • 特点:

    • 通用性非常强
  • 安装:

    • pip3 install lxml
  • 导包:

    • from lxml import etree
  • xpath的解析原理

      1. 实例化一个etree对象, 将页面源码加载到该对象中
      1. 使用该对象中的xpath方法结合着xpath表达式进行标签的文本和属性的提取
  • 实例化对象的方法:

    • 本地加载:
      • tree = etree.parse("./test_page.html")
      • tree.xpath('xpath表达式') # 注意这里最好是使用单引号,不解释, 一会就明白
    • 网络加载:
      • tree = etree.HTML(page_text)
      • tree.xpath('xpath表达式')
  • xpath表达式 /: 从标签开始实现层级定位 //: 从任意位置实现标签的定位

    属性定位:

      语法: tag[@attrName="attrValue"]
      //div[@class="song"]  # 找到class属性值为song的div标签

    层级&索引定位:

      # 注意索引值是从1开始
      //div[@class="tang"]/ul/li[2]/a  # 找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a

    逻辑运算:

      //a[@href="" and @class="du"]  # 找到href属性值为空且class属性值为du的a标签

    模糊匹配:

      //div[contains(@class, "ng")]
      //div[starts-with(@class, "ta")]

    取文本:

      //div[@class="song"]/p[1]/text()  # 取直系文本内容
      //div[@class="tang"]//text()  # 取所有文本内容

    取属性:

      //div[@class="tang"]//li[2]/a/@href

1、爬取58二手房的房源信息(列表页爬取标题和价格, 详情页爬取概况)

# 需求: 爬取58二手房的房源信息(列表页爬取标题和价格, 详情页爬取概况)
import requests
from lxml import etree
from decode_handler import get_crack_text, base64_code

url = "https://sz.58.com/ershoufang/?PGTID=0d100000-0000-43ff-252a-3c9a606fba70&ClickID=2"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
}

# 获取页面源码数据
page_text = requests.get(url=url, headers=headers).text

# 实例化etree对象,进行数据解析
tree = etree.HTML(page_text)
li_list = tree.xpath('//ul[@class="house-list-wrap"]/li')

all_data_list = list()
for li in li_list:
    title = li.xpath('./div[2]/h2/a/text()')[0]  # ./表示的就是我的当前标签(li标签)
    price_list = li.xpath('./div[3]//text()')
    price = "".join(price_list)
    detail_url = li.xpath('./div[2]/h2/a/@href')[0]

    # 向详情页的URL发送请求,获取详情页的概况数据
    detail_page_text = requests.get(url=detail_url, headers=headers).text
    
    # 再新实例化一个详情页的etree对象,进行详情页的数据解析
    detail_tree = etree.HTML(detail_page_text)
    desc = "".join(detail_tree.xpath('//div[@id="generalSituation"]/div//text()'))
    
    dic = {
        "title": title,
        "price": price,
        "desc": desc
    }
    all_data_list.append(dic)

print(all_data_list)
# 解析出所有城市名称https://www.aqistudy.cn/historydata/

tree.xpath('//div[@]/li/a/text() | //div[@]/ul/div[2]/li/a/text()')

八、作业

1、爬取贝壳网二手房源

# 需求:爬取贝壳网二手房源
import requests
from lxml import etree

url = "https://sz.ke.com/api/newhouserecommend?type=1&query=https%3A%2F%2Fsz.ke.com%2Fershoufang%2F"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
}

# 获取页面源码数据
page_text = requests.get(url=url,headers=headers).text

# 实例化etree对象,进行数据解析
tree = etree.HTML(page_text)
li_list = tree.xpath('//ul[@class="sellListContent"]/li')
print(li_list)

all_data_list=list()
for li in li_list:
    title=li.xpath('./div/div/a/@title')[0]
    print(title)
    price=li.xpath('./div/div[2]/div[5]/div//@title')[0]
    print(price)
    datail_url=li.xpath('./a/@href')[0]
    print(datail_url)
    
    # 向详情页的url发送请求,获取详情页的概况数据
    detail_page_text = requests.get(url=detail_url,headers=headers).text
    
    # 再实例化一个详情页的etree对象,进行详情页的数据解析
    detail_tree = etree.HTML(detail_page_text)
    desc = "".join(detail_tree.xpath('//div[@class="content"]ul/li//text()'))
    
    dic = {
        "title": title,
        "price": price,
        "desc": desc
    }
    all_data_list.append(dic)
    
print(all_data_list)    

2、获取彼岸汽车4K图片

# 获取彼岸汽车4K图片
import requests
from lxml import etree
import os

url="http://pic.netbian.com/4kqiche/"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
}
if not os.path.exists("./qiche/"):
    os.mkdir("./qiche/")

# 获取页面源码数据
page_text=requests.get(url=url,headers=headers).text

# 实例化etree对象,进行数据解析
tree = etree.HTML(page_text)
li_list=tree.xpath('//ul[@class="clearfix"]/li')  # li标签的对象


print(li_list)


for li in li_list:
    img_url="http://pic.netbian.com" + li.xpath('./a/img/@src')[0]
    img_name=li.xpath('./a/b/text()')[0].encode('iso-8859-1').decode('gbk')  # 处理编码
    
    print(img_name)
    
    # 向详情页的URL发送请求,获取详情页的图片数据
    img_page=requests.get(url=img_url,headers=headers).content
    
    with open('./qiche/'+img_name+'.jpg','wb') as f:
        f.write(img_page)

 3、爬取百度贴吧的评论内容

# 爬取百度贴吧的评论内容
import requests
from lxml import etree

url = "https://tieba.baidu.com/p/5126900475"
comment_url = "https://tieba.baidu.com/p/totalComment?t=1578445848467&tid=6320163250&fid=59099&pn=1&see_lz=0"

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

page_text = requests.get(url=url, headers=headers).text

tree = etree.HTML(page_text)
div_list = tree.xpath('//div[@class="l_post l_post_bright j_l_post clearfix  "]')

all_data_list = list()
for div in div_list:
    desc = div.xpath('./div[2]/div[1]/cc/div[2]//text()')
    all_data_list.append("".join(desc).strip())

print(all_data_list)

4、爬取http://pic.netbian.com/4kqiche/上面的汽车图片和标题

import requests
from lxml import etree

url = "http://pic.netbian.com/4kqiche/"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
}

response = requests.get(url=url, headers=headers)
# response.encoding = "utf-8"  # 对响应对象进行编码处理

page_text = response.text

tree = etree.HTML(page_text)
li_list = tree.xpath('//ul[@class="clearfix"]/li')

for li in li_list:
    img_url = "http://pic.netbian.com" + li.xpath('./a/img/@src')[0]
    title = li.xpath('./a/b/text()')[0]
    title = title.encode("iso-8859-1").decode("gbk") # 如果针对响应对象处理编码不成功的话,需要针对出现乱码的数据单独进行编码处理
    
    print(img_url, title)

猜你喜欢

转载自www.cnblogs.com/youhongliang/p/12694573.html