正则解析

回顾

  • 问题:
    • ip被封:代理
    • 请求参数问题:
      • 动态变化的请求参数
      • 加密的请求参数
    • 响应数据的问题:
      • cookie
      • 请求参数
    • 加密:
      • js逆向
  • 重点内容
    • 参数的动态化
      • data/prames
    • 反爬机制:
      • robots.txt
      • UA检测
      • 动态加载的数据
        • 如何检测数据是否为动态加载
        • 如何捕获动态加载的数据
      • 动态加载的数据是如何生成?
        • ajax
        • js

数据解析

  • 作用:实现聚焦爬虫
  • 实现方式:
    • 正则
    • bs4:重点
    • xpath:重点
    • pyquery:自学
  • 数据解析的通用原理是什么?
    • 解析的一定是html页面的源码数据
      • 标签中存储的文本内容
      • 标签属性的属性值
        • 原理:
        • 标签定位
        • 取文本或者取属性
  • 爬虫实现的流程
    • 指定url
    • 发请求
    • 获取响应数据
    • 数据解析
    • 持久化存储

In [2]:

import requests
import re
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'
}

正则解析

单字符: . : 除换行以外所有字符 [] :[aoe] [a-w] 匹配集合中任意一个字符 d :数字 [0-9] D : 非数字 w :数字、字母、下划线、中文 W : 非w s :所有的空白字符包,括空格、制表符、换页符等等。等价于 [ f v]。 S : 非空白 数量修饰:

    * : 任意多次  >=0
    + : 至少1次   >=1
    ? : 可有可无  0次或者1次
    {m} :固定m次 hello{3,}
    {m,} :至少m次
    {m,n} :m-n次
边界:
    $ : 以某某结尾 
    ^ : 以某某开头
分组:
    (ab)  
贪婪模式: .*
非贪婪(惰性)模式: .*?

re.I : 忽略大小写
re.M :多行匹配
re.S :单行匹配

re.sub(正则表达式, 替换内容, 字符串)

In [ ]:

import re
#提取出python
key="javapythonc++php"
#####################################################################
#提取出hello world
key="<html><h1>hello world<h1></html>"
#####################################################################
#提取170
string = '我喜欢身高为170的女孩'
#####################################################################
#提取出http://和https://
key='http://www.baidu.com and https://boob.com'
#####################################################################
#提取出hit. 
key='bobo@hit.edu.com'#想要匹配到hit.
#####################################################################
#匹配sas和saas
key='saas and sas and saaas'
#####################################################################

In [3]:

key="javapythonc++php"
re.findall('python',key)

Out[3]:

['python']

In [4]:

#提取出hello world
key="<html><h1>hello world<h1></html>"
re.findall('<h1>(.*?)<h1>',key)

Out[4]:

['hello world']

In [6]:

#提取170
string = '我喜欢身高为170的女孩'
re.findall('d+',string)

Out[6]:

['170']

In [11]:

#提取出http://和https://
key='http://www.baidu.com and https://boob.com'
re.findall('https?://',key)

Out[11]:

['http://', 'https://']

In [13]:

#提取出hit. 
key='bobo@hit.edu.com'#想要匹配到hit.
re.findall('h.*?.',key)

Out[13]:

['hit.']

In [14]:

#匹配sas和saas
key='saas and sas and saaas'
re.findall('sa{1,2}s',key)

Out[14]:

['saas', 'sas']

In [16]:

url = 'http://duanziwang.com/category/搞笑图/'
#捕获到的是字符串形式的响应数据
page_text = requests.get(url=url,headers=headers).text

#数据解析
ex = '<div class="post-head">.*?<a href="http://duanziwang.com/d+.html">(.*?)</a></h1>'
re.findall(ex,page_text,re.S)#爬虫使用正则做解析的话re.S必须要使用

#持久化存储

Out[16]:

['比较下老婆和老妈,一比吓一跳_段子网收录最新段子',
 '搞笑夫妻:烦恼里面找快乐_段子网收录最新段子',
 '夫妻界的搞笑奇葩_段子网收录最新段子',
 '超囧冷人小夫妻_段子网收录最新段子',
 '雷人夫妻:吃泡面、偷看日记和生日送花_段子网收录最新段子',
 '脸皮薄的人难以成功_段子网收录最新段子',
 '12秒的雷政富和21秒李小璐_段子网收录最新段子',
 '从前有只麋鹿,它在森林里玩儿,不小心走丢了。于是它给它的好朋友长颈鹿打电话:“喂…我迷路啦。”长颈鹿听见了回答说:“喂~我长颈鹿啦~”_段子网收录最新段子',
 '最萌挡车球_段子网收录最新段子',
 '再高贵冷艳的喵星人! 也总有一天有被吓得屁滚尿流的时候。_段子网收录最新段子']

bs4解析

  • 环境安装:

    • pip install bs4
    • pip install lxml
  • 解析原理

    • 1.实例化一个BeautifulSoup的对象,需要将等待被解析的页面源码数据加载到该对象中
    • 2.需要调用BeautifulSoup对象中相关的属性和方法进行标签定位和文本数据的提取
  • BeautifulSoup如何实例化

    • 方式1:BeautifulSoup(fp,'lxml'),将本地存储的一张html文件中的指定数据进行解析
    • 方式2:BeautifulSoup(page_text,'lxml'),将从互联网中爬取到的数据直接进行数据解析
  • 标签定位

    • soup.tagName:定位到第一个出现的tagName标签
    • 属性定位:根据指定的属性进行对应标签的定位
      • soup.find('tagName',attrName='value')
      • soup.find_all('tagName',attrName='value')
    • 选择器定位:
      • soup.select('选择器')
      • 层级选择器:
        • 大于号:表示一个层级
        • 空格:表示多个层级
  • 取文本

    • tag.string:取出直系的文本内容
    • tag.text:取出所有的文本内容
  • 取属性

    • tag['attrName']

In [18]:

from bs4 import BeautifulSoup
fp = open('./test.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')
soup

. . .

In [28]:

soup.div
# soup.find('div',class_='song')
# soup.find('a',id='feng')
# soup.find_all('div',class_='song')
# soup.select('.tang')
# soup.select('#feng')
soup.select('.tang li')

. . .

In [38]:

soup.p.string
soup.p.text
soup.find('div',class_='tang').text
a_tag = soup.select('#feng')[0]
a_tag['href']

Out[38]:

'http://www.haha.com'

In [44]:

main_url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
page_text = requests.get(url=main_url,headers=headers).text

fp = open('./sanguo.txt','w',encoding='utf-8')

#数据解析
soup = BeautifulSoup(page_text,'lxml')
#解析出章节的标题&详情页的url
a_list = soup.select('.book-mulu > ul > li > a')
for a in a_list:
    title = a.string
    detail_url = 'http://www.shicimingju.com'+a['href']
    
    #捕获章节内容
    page_text_detail = requests.get(detail_url,headers=headers).text#获取了详情页的页面源码数据
    #数据解析:章节内容
    detail_soup = BeautifulSoup(page_text_detail,'lxml')
    div_tag = detail_soup.find('div',class_='chapter_content')

    content = div_tag.text
    
    fp.write(title+':'+content+'
')
    print(title,'下载成功!!!')
fp.close()

. . .

  • 图片数据的爬取
    • 基于requests
    • 基于urllib
    • 区别:能不能实现UA伪装

In [47]:

#基于requests
url = 'http://pic.netbian.com/uploads/allimg/190902/152344-1567409024af8c.jpg'
img_data = requests.get(url=url,headers=headers).content#content返回的是二进制类型的数据
with open('./123.png','wb') as fp:
    fp.write(img_data)

In [49]:

#基于urllib
from urllib import request
request.urlretrieve(url=url,filename='./456.jpg')

Out[49]:

('./456.jpg', <http.client.HTTPMessage at 0x217a8af3470>)

xpath解析

  • 环境安装:
    • pip install lxml
  • 解析原理
    • 实例化一个etree的对象,且将被解析的页面源码数据加载到该对象中
    • 使用etree对象中的xpath方法结合着不同形式的xpath表达式进行标签定位和数据的提取
  • 实例化对象:
    • etree.parse('filePath'):将本地存储的一个html文件中的数据加载到实例化好的etree对象中
    • etree.HTML(page_text)
  • xpath表达式
    • 标签定位:
      • 最左侧的/:必须从根节点开始定位标签(几乎不用)
      • 非最左侧的/:表示一个层级
      • 最左侧的//:可以从任意位置进行指定标签的定位(最常用)
      • 非最左侧的//:表示多个层级
      • 属性定位://tagName[@attrName="value"]
      • 索引定位://tagNamne[index],索引是从1开始
      • //div[contains(@class, "ng")]
      • //div[starts-with(@class, "ta")]
    • 取文本
      • /text():取出直系的文本内容
      • //text():取出的是所有的文本
    • 取属性
      • /@attrName

In [76]:

from lxml import etree
tree = etree.parse('./test.html')
tree.xpath('/html/head/meta')
tree.xpath('/html//meta')
tree.xpath('//meta')
tree.xpath('/meta')#error
tree.xpath('//p')
tree.xpath('//div[@class="tang"]')
tree.xpath('//li[1]')
tree.xpath('//a[@id="feng"]/text()')[0]
tree.xpath('//div[@class="tang"]//text()')
tree.xpath('//a[@id="feng"]/@href')

Out[76]:

['http://www.haha.com']

重点:局部解析的时候./表示的含义

In [86]:

import os

In [88]:

url = 'http://pic.netbian.com/4kmeinv/'
page_text = requests.get(url=url,headers=headers).text

dirName = 'imgLibs'
if not os.path.exists(dirName):
    os.mkdir(dirName)

#数据解析
tree = etree.HTML(page_text)
#xpath是基于一整张页面源码进行数据解析
img_list = tree.xpath('//div[@class="slist"]/ul/li/a/img')

#局部数据解析
for img in img_list:
    #./表示的是当前标签,xpath的调用者就是当前标签
    img_src = 'http://pic.netbian.com'+img.xpath('./@src')[0]
    img_name = img.xpath('./@alt')[0]+'.jpg'
    img_name = img_name.encode('iso-8859-1').decode('gbk')
    
    filePath = './'+dirName+'/'+img_name
    request.urlretrieve(img_src,filename=filePath)
    print(img_name,'下载成功!!!')

. . .

In [90]:

#全站操作
#1.指定一个通用的url模板:用来生成不同页码对应的url,模板是不可变
url = 'http://pic.netbian.com/4kmeinv/index_%d.html'
dirName = 'imgLibs'
if not os.path.exists(dirName):
    os.mkdir(dirName)
    
for pageNum in range(1,6):
    if pageNum == 1:
        page_url = 'http://pic.netbian.com/4kmeinv/'
    else:
        page_url = format(url%pageNum)

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

    #数据解析
    tree = etree.HTML(page_text)
    #xpath是基于一整张页面源码进行数据解析
    img_list = tree.xpath('//div[@class="slist"]/ul/li/a/img')

    #局部数据解析
    for img in img_list:
        #./表示的是当前标签,xpath的调用者就是当前标签
        img_src = 'http://pic.netbian.com'+img.xpath('./@src')[0]
        img_name = img.xpath('./@alt')[0]+'.jpg'
        img_name = img_name.encode('iso-8859-1').decode('gbk')

        filePath = './'+dirName+'/'+img_name
        request.urlretrieve(img_src,filename=filePath)
        print(img_name,'下载成功!!!')

. . .

In [ ]:

python
原文地址:https://www.cnblogs.com/bky20061005/p/12145691.html