Python爬虫入门——数据提取与清晰策略

正则表达式

表达式


说明

.

除了\n和\r的所有字符

\d

数字

\D

非数字

\w

数字字母和下划线

\W

非数字字母和下划线

\s

空格(包括制表符、换页符)

-------------------------------

-------------------------------------

[a-z]

小写应为字母

[a-zA-Z0-9]

大小写英文字母与数字

[123]

数字123

[^ 123]

不是数字123

*

出现次数>=0

+

出现次数>=1

{n}

出现次数=n

{n,m}

m>=出现次数>=n

^

以开头

$

以结尾


关闭贪婪模式

()

用于获取括号内匹配成功的字符串

  1. 案例

定义密码的正则表达式:
规则:英文字母开头,可以包括数字、大小写英文字母、下划线,6-16位

password_pattern = '^ [a-zA-Z]{1}[a-zA-Z0-9_]{5-15}$'
#等价于
password_pattern = '^ [a-zA-Z][a-zA-Z0-9_]{5-15}$'
#匹配div标签,class='class1'中的文本内容:
	<div class='class1'>要匹配的内容</div>
	div_pattern = '<div class='class1'>(.*)</div>'
#匹配的结果为:
	<div class='class1'>**要匹配的内容**</div>

#当匹配div标签,class='class1'中的文本内容为:
	<div><div class='class1'>要匹配的内容</div></div>
	div_pattern = '<div class='class1'>(.*)</div>'
#匹配的结果为:
	<div><div class='class1'>**要匹配的内容</div>**</div>
#正则表达式默认开启贪婪模式,默认匹配尽可能多的字符串
#取消贪婪模式:
	div_pattern = '<div class='class1'>(.*?)</div>'
#匹配结果为:
	<div><div class='class1'>**要匹配的内容**</div></div>

re模块使用案例

  1. 提取
  2. 匹配
  3. 替换
提取
#导入re模块
import re
#findall方法
ret = re.findall(【正则表达式】,【被提取的字符串】)
#注:返回的类型是列表,如果未匹配成功返回一个空列表
匹配
import re
#match方法
ret = re.match(【正则表达式】,【被匹配的字符串】)
#注:匹配密码
#    如果匹配成功,返回<claa're.Match'>对象
#    如果匹配不成功,返回None
替换
import re
# sub方法
ret = re.sub(【正则表达式】,【替换成的字符串】,【被替换的字符串】)
三种方法的使用
import re

with open('index.html','r',encoding='utf-8') as f:
    html = f.read()
    #替换文件中换行符
    html = re.sub('\n','',html)
    print(html)
    #提取数据
    pattern_1 ='<div class="email">(.*?)</div>'
    ret_1 = re.findall(pattern_1,html)
    #去掉空格
    print(ret_1[0].strip())
#匹配密码
password_pattern = r'^[a-zA-Z][a-zA-Z0-9_]{5,15}$'
pass1 = '1234567'
pass2 = 'k123456'
pass3 = 'k123'
print(re.match(password_pattern,pass1))
print(re.match(password_pattern,pass2))
print(re.match(password_pattern,pass3))

提取商城分类结构

对下面HTML文件进行提取

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSDN微课商城</title>
    <link rel="stylesheet" href="../css/main.css">
    <script type="text/javascript" src="../js/main.js"></script>
</head>
<body>

<div id="register" hidden="hidden">
    <h2 class="form_p">注册</h2>
    <p id="register_message">
        <!--信息有误-->
    </p>
    <form action="#" method="post" id="register_form">
        <input id="register_account" type="text" name="account" placeholder="账号(数字、英文、下换线,8-16位)"><br/>
        <input id="register_password" type="password" name="password" placeholder="密码(数字、英文、下换线,6-16位)"><br/>
        <!--<input type="password" name="repassword" placeholder="确认密码"><br/>-->
        <input id="register_submit" type="submit" value="注册">
    </form>
</div>

<div id="login" hidden="hidden">
    <h2 class="form_p">登录</h2>
    <p id="login_message">
        <!--信息有误-->
    </p>
    <form action="#" method="post" id="login_form">
        <input id="login_account" type="text" name="account" placeholder="账号"><br>
        <input id="login_password" type="password" name="password" placeholder="密码"><br>
        <input id="login_submit" type="submit" value="登录">
    </form>
</div>

<header>
    <span class="title"> <a href="index.html">CSDN微课商城</a> </span>
    <span>
        <form action="#" class="search_form">
            <input type="text" name="course" placeholder="按课程名称搜索">
            <input type="submit" value="搜索">
        </form>
    </span>
    <span class="user">
        <a href="javascript:show('login')">登录</a>/
        <a href="javascript:show('register')">注册</a>
        <!-- 已经登录显示的内容 -->
        你好:
        <a href="user.html">用户1</a>
        <a href="#">注销</a>
    </span>
</header>

<article>
    <section class="nav_section"><img src="../img/csdn_static/2.png" alt="" width="100%"></section>
    <section class="main_section"><h1>第一章 路由与模板</h1>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">Web原理与框架简介</span><span class="price">¥75</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">Django环境搭建与入门案例</span><span class="price">¥153</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">基本路由映射与命名空间</span><span class="price">¥154</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">正则路由映射参数的传递与接收</span><span class="price">¥177</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">反向解析处理器</span><span class="price">¥161</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">Request对象与Response对象</span><span class="price">¥44</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">上下文与模板调用</span><span class="price">¥97</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">模板层基础语法</span><span class="price">¥105</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">模板过滤器</span><span class="price">¥133</span></figcaption>
        </a></figure>
    </section>
    <section class="main_section"><h1>第二章 模型类实现</h1>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">ORM原理与数据库配置</span><span class="price">¥143</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">表与字段的定义和常用字段约束</span><span class="price">¥118</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">数据迁移与维护</span><span class="price">¥57</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">模型类的增删改</span><span class="price">¥45</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">模型类的查询方法</span><span class="price">¥187</span></figcaption>
        </a></figure>
        <figure><a href="course.html"> <img src="../img/course/course.png">
            <figcaption><span class="course_name">QuerySet详解</span><span class="price">¥197</span></figcaption>
        </a></figure>
    </section>
</article>

<footer>
    <div id="footer_div1">
        <p><a href="#">关于我们</a>| <a href="#">招聘</a>| <a href="#">广告服务</a>| <a href="#">网站地图</a></p>
        <p><a href="#">QQ客服</a>| <a href="#">kefu@csdn.ent</a>| <a href="#">客服论坛</a>| <a href="#">400-660-0108</a>| <a
                href="#">工作时间:8:30-22:00</a></p>
        <p> 百度提供站内搜索 北ICP备19004658 </p>
        <p> ©1999-2019 北京创新乐知网络技术有限公司 </p>
        <p> 版权申诉 家长监护 经营性网站备案信息 网络110报警服务 中国互联网举报中心 北京互联网违法和不良信息举报中心 </p>
    </div>
    <div id="footer_div2">
        <figure><img src="../img/csdn_static/二维码1.png">
            <figcaption>CSDN咨询</figcaption>
        </figure>
        <figure><img src="../img/csdn_static/二维码1.png">
            <figcaption>CSDN学院</figcaption>
        </figure>
        <figure><img src="../img/csdn_static/二维码1.png">
            <figcaption>CSDN企业招聘</figcaption>
        </figure>
    </div>
</footer>

</body>
</html>

提取过程

import re

with open('static/html/index.html','r',encoding='utf-8') as f:
    #去掉换行符
    html =re.sub('\n','',f.read())
    #print(html)
    #提取课程种类
    #建立正则表达式
    section_pattern = '<section class="main_section">(.*?)</section>'
    section_s = re.findall(section_pattern,html)
    print(section_s)
    print(len(section_s))
    #建立课程种类的正则表达式
    category_pattern = '<h1>(.*?)</h1>'
    #建立课程名称的正则表达式
    course_pattern ='<span class="course_name">(.*?)</span><span class="price">'
    #建立一个列表
    data_s=[]
    #遍历section_s
    for section in section_s:
        #在section中取到课程种类对象
        category = re.findall(category_pattern,section)
        #取到课程种类对象列表中的课程种类信息
        #print(category[0])
        course_s = re.findall(course_pattern,section)
        data_s.append(
            {
                'category':category,
                'course_s':course_s
            }
        )
    print(data_s)
    for data in data_s:
        print(data.get('category'))
        for course in course_s:
            print('    ',course)

提取结果

C:\Users\Lenovo\AppData\Local\Programs\Python\Python38\python.exe C:/Users/Lenovo/PycharmProjects/提取商城分类结构/re_index.py
['<h1>第一章 路由与模板</h1>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">Web原理与框架简介</span><span class="price">¥75</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">Django环境搭建与入门案例</span><span class="price">¥153</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">基本路由映射与命名空间</span><span class="price">¥154</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">正则路由映射参数的传递与接收</span><span class="price">¥177</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">反向解析处理器</span><span class="price">¥161</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">Request对象与Response对象</span><span class="price">¥44</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">上下文与模板调用</span><span class="price">¥97</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">模板层基础语法</span><span class="price">¥105</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">模板过滤器</span><span class="price">¥133</span></figcaption>        </a></figure>    ', '<h1>第二章 模型类实现</h1>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">ORM原理与数据库配置</span><span class="price">¥143</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">表与字段的定义和常用字段约束</span><span class="price">¥118</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">数据迁移与维护</span><span class="price">¥57</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">模型类的增删改</span><span class="price">¥45</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">模型类的查询方法</span><span class="price">¥187</span></figcaption>        </a></figure>        <figure><a href="course.html"> <img src="../img/course/course.png">            <figcaption><span class="course_name">QuerySet详解</span><span class="price">¥197</span></figcaption>        </a></figure>    ']
2
[{'category': ['第一章 路由与模板'], 'course_s': ['Web原理与框架简介', 'Django环境搭建与入门案例', '基本路由映射与命名空间', '正则路由映射参数的传递与接收', '反向解析处理器', 'Request对象与Response对象', '上下文与模板调用', '模板层基础语法', '模板过滤器']}, {'category': ['第二章 模型类实现'], 'course_s': ['ORM原理与数据库配置', '表与字段的定义和常用字段约束', '数据迁移与维护', '模型类的增删改', '模型类的查询方法', 'QuerySet详解']}]
['第一章 路由与模板']
     ORM原理与数据库配置
     表与字段的定义和常用字段约束
     数据迁移与维护
     模型类的增删改
     模型类的查询方法
     QuerySet详解
['第二章 模型类实现']
     ORM原理与数据库配置
     表与字段的定义和常用字段约束
     数据迁移与维护
     模型类的增删改
     模型类的查询方法
     QuerySet详解

XPath语法与案例

  1. 谷歌浏览器(任意)配置XPath插件
  2. XPath常用语法
  3. XPath应用案例
XPath常用语法

表达式

描述

/

根节点选取或下级

//

任意节点,不考虑位置

.

当前节点


当前节点的父节点

@

选取属性

*

匹配任何节点

【nodename】

根据节点筛选

contains(@属性,‘包含的内容’)

模糊查询

text()

文本内容

注:XPath中的索引从1开始

代码实际应用

一级分类:	//h3[@class="classify_c_h3"]/a/text()
二级分类:	//div[@class="classify_list"]/span/a/text()
			//div[contains(@class,"classify_list")]/span/a/text()

Python中的lxml模块

实战数据提取CSND学院主页数据

截取操作代码

import lxml.etree as le

with open('edu.html','r',encoding='utf-8') as f:
    html = f.read()
    html_x = le.HTML(html)
    #print(html_x)
    div_x_s = html_x.xpath('//div[@class="classify_cList"]')
    #print(div_x_s)
    data_s = []
    for div_x in div_x_s:
        category1=div_x.xpath('./h3/a/text()')[0]
        #print(category1)
        category2_s = div_x.xpath('./div/span/a/text()')
        #print(category2_s)
        data_s.append(
            dict(
                category1=category1,
                category2_s=category2_s
                )
        )
        #print(data_s)
        for data in data_s:
            print(data.get('category1'))
            for category2 in data.get('category2_s'):
                print('    ',category2)

百度针对XPath 爬虫的反扒策略与解决方式

读取正常百度数据
import lxml.etree as le
with open('meiju1.html','r',encoding='utf-8') as f:
    html = f.read()
    html_x = le.HTML(html)
    title_s = html_x.xpath('//div[contains(@class,"threadlist_title pull_left j_th_tit")]/a/text()')
    print(title_s)
    for title in title_s:
        print(title)
读取被注释掉的百度数据
import lxml.etree as le
import re
with open('meiju2.html','r',encoding='utf-8') as f:
    html = re.sub('\n','',f.read())
    title_pattern = '<div class="threadlist_title pull_left j_th_tit ">.*?<a.*?>(.*?)</a>'
    title_s = re.findall(title_pattern,html)
    for title in title_s:
        print(title)

JsonPath使用案例

dumps和loads用法

import json

python_data = [
    {
        'username':'name1',
        'vip':True
    },
    {
        'username':None,
        'vip':False,
    }
]

#dumps 用于把Python对象转换成Json对象
json_data = json.dumps(python_data)
print(json_data)
print(type(json_data))
#loads 用于把Json对象转换成Python对象
python_data2 = json.loads(json_data)
print(python_data2)
print(type(python_data2))

dump和load用法

import json

python_data = [
    {
        'username':'name1',
        'vip':True
    },
    {
        'username':None,
        'vip':False,
    }
]

#dump 用于把Python类型的数据转换成Json类型的字符串,保存到本地
json.dump(python_data,open('json.txt','w'))
#load 用于读取本地json数据本转换成python对象
python_data2=json.load(open('json.txt'))
print(python_data2)