python爬虫理论复习

第一章 web网站与访问

1.1 POST方法向网站发送数据、GET+POST混合方法向网站发送数据

GETPOSTGET+POST
用途、语义上信息获取(查询)资源请求(增删改)信息或资源的(增删改查)
传参方式URL传值表单传值(request body 传参)URL传值+表单传值
服务器端获取数据方法argsform(args+form)/values
特点适用于发送数据较小的场景;后退、刷新无害,速度快;书签可被收藏缓存,所有人可见,安全性差适用于发送数据较大的场景;后退、刷新需要重新提交数据,速度慢;书签不可收藏、不能缓存,不可见,更安全适用于所有场景,优缺点融合

1.2 Web下载文件

服务器向客户端发送文件名称和文件数据的过程

1.启动服务器,返回可下载文件名称到客户端
2.发送拟下载的文件名称到服务器端
3.获取拟下载文件名称并返回文件的数据到客户端
4.客户端接收并保存数据
服务器端
客户端

1.3 Web上传文件

客户端把文件发送到服务器(服务器接收数据的过程)

1.启动服务器
2.客户端组织好上传的文件,并发送到服务器端
3.服务器获取拟上传文件名称和数据,保存到服务器端
服务器端
客户端

1.4 正则表达式

操作符说明实例
.任何单个字符
[]字符集[abc]表示a、b、c,[a-z]表示a到z单个字符
[^]非字符集(排除范围)[^abc]表示非a非b非c的单个字符
*前一个字符0次或无限次扩展abc*表示ab、abc、abcc、abccc等
+前一个字符1次获无限次扩展abc+表示abc、abcc、abccc等
?前一个字符0次或1次扩展abc?表示ab、abc
左右表达式任意一个abc|def表示abc、def
{m}扩展前一个字符m次ab{2}c表示abbc
{m,n}扩展前一个字符m至n次(含n)ab{1,2}c表示abc、abbc
^匹配字符串开头^abc表示abc且在一个字符串的开头
$匹配字符串结尾abc$表示abc且在一个字符串的结尾
()分组标记,内部只能使用操作符(abc)表示abc,(abc|def)表示abc、def
\d数字,等价于[0-9]
\w单词字符,等价于[A-Za-z0-9_],A-Z和a-z以及数字和下划线
\s匹配到一个空白字符(\n, \t, \r, 空格)

1.4.1 正则表达式的使用

import re   # python标准库,用于字符串匹配
reg = r"\d+"    # 表示匹配连续的多个数值,在这里表示匹配连续多个数字
m = re.search(reg, "abc123cd")
print(m)

# 结果:
<_sre.SRE_Match object; span=(3,6), match='123'>
# 找到连续的数值:“123”,span(3,6)表示开始位置是3,结束位置是6

1.4.2 经典正则表达式

表达式表示的字符串
^[A-Za-z]+$由26个字母组成的字符串
^[A-Za-z0-9]+$由26个字母和数字组成的字符串
^-?\d+$整数形式的字符串
^[0-9]*[1-9][0-9]*$正整数形式的字符串
[1-9]\d{5}中国境内邮政编码,6位
\u4e00-\u9fa5匹配中文字符
d{3}-\d{8}|\d{4}-\d{7}国内电话号码,010-73849573

1.4.3 Re库主要功能函数

函数说明
re.search()一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
re.match()从一个字符串的开始位置起匹配正则表达式,返回match对象
re.findall()搜索字符串,以列表类型返回全部能匹配的子串
re.split()按照正则表达式匹配结果进行分割,返回列表类型
re.finditer()搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象
re.sub()在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串

1.4.4 Re库另一种等价用法

import re
match = re.search(r'[1-9]\d{5}','BIT100081')

等价于:
pat = re.compile(r'[1-9\d{5}]') # 编译为正则表达式对象
match = pat.search('BIT100081')

第二章web网页数据爬取方法BeautifulSoup

from bs4 import BeautifulSoup
soup = BeautifulSoup('<p>data<\p>', 'html.parser')

bs4库的prettity() 方法,soup.prettity()补全html文档

2.1 BeautifulSoup查找文档元素

  • 基本元素:
    • .name,获取标签名称
    • .attrs,获取标签内所有属性,返回一个字典
    • .string,获取标签的文本信息,如果标签内包含了多个子节点并有多个文本时返回None

2.2 BeautifulSoup遍历文档元素

标签类型标签迭代类型
.contents, .parent, .next_sibling, .previous_sibling.children, .parents, .descendants, .next_siblings, .previous_siblings
# 获取父·祖先节点
print(soup.p.parent)  # 获取p标签的直接父节点
print(soup.p.parents)  # 获取p标签的祖先节点,返回一个生成器
# 获取子·子孙节点
print(soup.p.contents)  # 获取p标签内的直接子节点,返回一个列表
print(soup.p.children)  # 获取p标签内的直接子节点,返回一个生成器
print(soup.p.descendants)  # 获取p标签内的子孙节点,返回一个生成器
# 获取兄弟节点
print(soup.a.previous_sibling)  # 获取a标签的上一个兄弟节点
print(soup.a.previous_siblings)  # 获取a标签前面的所有兄弟节点,返回一个生成器
print(soup.a.next_sibling)  # 获取a标签的下一个兄弟节点
print(soup.a.next_siblings)  # 获取a标签后面的所有兄弟节点,返回一个生成器

2.2.1 使用方法选择器

  • find() 返回匹配到的第一个结果
  • find_all() 返回一个包含所有匹配结果的列表
print(soup.find_all(text=re.compile('Lacie'), limit=2))  # 使用正则获取所有文本包含'Lacie'的节点(limit: 限制匹配个数)
print(soup.find_all('a', text='Lacie'))  # 获取所有a标签内文本等于'Lacie'的节点(文本完整匹配)
print(soup.find_all('a', id='link2'))  # 获取所有a标签内id等于'link2'的节点
print(soup.find_all('a', class_='sister'))  # 获取所有a标签内class等于'sister'的节点
print(soup.find_all('a', class_='sister', id='link2'))  # 多个搜索条件叠加
print(soup.find_all(name='a'))  # 获取所有a节点
print(soup.find_all(attrs={'class': 'sister'}))  # 获取所有class属性值为'sister'的节点

2.3 使用CSS语法查找元素

2.3.1 使用CSS语法

  • 调用规则:tag.select(css)
  • 一般结构:[tagName][attName[=value]]

2.3.2 语法规则

选择器描述
[attName]选取带有指定属性的字符串
[attName=value]选取带有指定属性和值的字符串
[attName^=value]匹配属性值以指定值开头的每个元素
[attName$=value]匹配属性值以指定值结尾的每个元素
[attName*=value]匹配属性值包含指定值的每个元素

2.3.3 select查找

select查找子孙节点select查找直接子节点select查找兄弟节点
div pdiv>pdiv~p,后续所有同级别的节点;div+p,后续第一个同级别的兄弟节点
print(soup.select('p'))  # 获取所有p标签,返回一个列表
print(soup.select('p a'))  # 获取所有p标签内的a节点,返回一个列表
print(soup.select('p.story'))  # 获取p标签内class为'story'的所有元素,返回一个列表
print(soup.select('.story'))  # 获取class为'story'的所有元素,返回一个列表
print(soup.select('.beautiful.title'))  # 获取class为'beautiful title'的所有元素,返回一个列表
print(soup.select('#link1'))  # 获取id为'link1'的所有元素,返回一个列表

第三章 网站数据爬取路径

3.1 网站树的爬取路径

在这里插入图片描述

  • 递归程序实现
    • 分治、直接间接调用自身
  • 深度优先遍历(DFS)
    • 后进先出,栈,list
  • 广度优先遍历(BFS)
    • 先进先出,队列,list

递归分治:一棵树的遍历划分为根结点和它子树们的遍历

3.2 网站图的爬取路径

如果每个网页都能回到主界面,那么网站的关系就是一个有回路的图
在这里插入图片描述

3.3 python的前后台线程

  • setDaemon(True):设置后台线程,守护线程
    • 主线程退出时后台线程随机退出,优先级较低,用于为其他线程提供服务
    • 线程的等待:线程对象.join(),该线程完成后才能继续往下运行
    • 多线程与资源:
      lock = threading.RLock()
      lock.acquire()  # 获取锁
      ......
      lock.release()  # 释放锁
      
  • setDaemon(False)(默认情况)非守护线程,也称为前台线程
    • 主线程退出时,若前台线程还未结束,则等待所有前台线程结束,相当于在程序末尾加入join()
    • 多线程与资源(前后台线程)

第四章 Scrapy框架爬虫程序

4.1 Scrapy爬虫框架介绍

4.1.1 Scrapy爬虫框架结构

5+2结构,分布式,3条数据流路径

在这里插入图片描述

模块功能
Engine控制各模块数据流,不间断从Scheduler处获得爬取请求,直至请求为空
Spider框架入口(初始爬取请求)。解析Downloader返回的响应(Response),产生爬取项(scraped item),产生额外的爬取请求(Request)
Item Pipelines框架出口(爬取结果及处理)以流水线方式处理Spider产生的爬取项
Scheduler对所有爬取请求进行调度管理
Spider Middleware对请求和爬取项的再处理(修改、丢弃、新增请求或爬取项)
Downloader根据请求下载网页
Downloader Middleware实施Engine、Scheduler和Downloader之间进行用户可配置的控制(修改、丢弃、新增请求或响应)

4.1.2 Scrapy命令行的使用

>scrapy <command> [options] [args]

命令说明格式
startproject创建一个新工程scrapy startproject <name> [dir]
genspider创建一个爬虫scrapy genspider [options] <name> <domain>
settings获得爬虫配置信息scrapy settings [options]
crawl运行一个爬虫scrapy crawl <spider>
list列出工程中所有爬虫scrapy list
shell启动URL调试命令行scrapy shell [url]

4.1.3 scrapy与request对比

requestScrapy
相同点1.实现python爬虫重要技术路线 2.可用性都好,文档丰富,入门简单3.两者都没有处理js、提交表单、应对验证码等功能(可扩展)
不同点页面级爬虫网站级爬虫
功能库框架
并发性考虑不足,性能较差并发性好,性能较高
重点在于页面下载重点在于爬虫结构
定制灵活一般定制灵活,深度定制困难
上手十分简单入门稍难

4.1.4 yield关键字和生成器

在这里插入图片描述

生成器相比一次列出所有内容的优势

  • 更节省存储空间
  • 响应更迅速
  • 使用更灵活

4.1.5 Scrapy爬虫的数据类型

4.1.5.1 Request类

Request对象表示一个HTTP请求,由Spider生成,由Downloader执行

属性或方法说明
.urlRequest对应的请求URL地址
.method对应的请求方法,GET POST
.headers字典类型风格的请求头
.body请求内容主体,字符串类型
.meta用户添加的扩展信息,在Scrapy内部模块间传递信息使用
.copy()复制该请求
4.1.5.2 Response类

Response对象表示一个HTTP响应,由Downloader生成,由Spider处理

属性或方法说明
.urlResponse对应的URL地址
.statusHTTP状态码,默认是200
.headersResponse对应的头部信息
.bodyResponse对应的内容信息,字符串类型
.flags一组标记
.request产生Response类型对应的Request对象
.copy()复制该响应
4.1.5.3 Item类

Item对象表示一个从HTML页面中提取的信息内容,由Spider生成,由Item Pipeline处理Item,类似字典类型,可以按照字典类型操作

4.2 Scrapy中查找HTML元素Xpath

路径表达式+索引+属性

xpath的索引值从1开始

4.2.1 Xpath常用表达式

表达式描述例子
nodename选取此节点body,选取body元素
/绝对路径,表示当前节点的下一级节点元素/body,当前节点下一级的body元素,默认当前节点选取根元素
//相对路径,全文档查找//title,全文档搜索title元素;body//title,在body元素后代中搜索所有title元素
.当前节点.//title,在当前节点后代中搜索所有title元素
@选取属性//node[@attribute],包含attribute属性的节点node
*通配符/*,绝对路径匹配任意节点;//*,全文匹配任意节点;@*,匹配任意属性

4.3 Scrapy爬取和存储数据

总结:

  • scrapy把数据爬取数据存储分开处理,他们都是异步执行的,mySpider每爬取一个数据项目item,就yield推送给pipelines.py程序存储
  • 等待存储完毕后又再次爬取item再次推送再次存储
  • 以上过程一直进行直到爬取过程结束

第五章 爬取网站商品数据

Selenium脚本执行时后端六条实现的流程:

  • 对于每一条Selenium脚本,一个http请求会被创建并且发送给浏览器的驱动
  • 浏览器驱动中包含了一个HTTP Server,用来接收这些http请求
  • HTTP Server接收到请求后根据请求来具体操控对应的浏览器
  • 浏览器执行具体的测试步骤
  • 浏览器将步骤执行结果返回给HTTP Server
  • HTTP Server又将结果返回给Selenium的脚本,如果是错误的http代码我们就会在控制台看到对应的报错信息

5.1 Selenium编写爬虫程序

  • 程序先从selenium引入webdriver,引入chrome程序的选择项目Options:
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    
  • 设置启动chrome时不可见
    chrome_options.add_argument('-headless')
    chrome_options.add_argument('-disable-gpu')
    
  • 创建chrome浏览器
    driver = webdriver.Chrome(chrome_options=chrome_options)
    
    • 这样创建的chrome浏览器是不可见的,仅仅使用:
      driver = webdriver.Chrome()
      
    • 创建chrome浏览器,那么在程序执行时会弹出一个chrome浏览器
  • 使用driver.get(url)方法访问网页
    driver.get("http://127.0.0.1:5000")
    
  • 通过driver.page_source获取网页HTML代码(渲染后的数据页面)
    html = driver.page_source
    
  • driver.get_cookies():获得页面的cookies
  • driver.current_url:查看请求的URL

5.2 Selenium爬取Ajax网页数据

Ajax网页数据:后台与服务器进行少量数据交换,异步更新部分网页

模拟浏览器对下拉选项的点击选择,获得动态交互加载出更新后的网页数据

5.3 Selenium等待HTML元素

为什么要等待html元素?
HTML元素还没加载完毕,无法获得该元素的控制和访问

  • 强制等待1.5秒
    time.sleep(1.5)
    
  • 隐性等待1.5秒,即网页在加载时等待1.5秒
    driver.implicitly_wait(1.5)
    
  • 循环等待
    waitTime = 0
    while waitTime < 10:
        marks = driver.find_element(By.XPATH, '//select/option')
        if len(marks) > 0:
            break
        time.sleep(0.5)
        waitTime += 0.5
        if waitTime >= 10:
            raise Exception("Waiting time out")
    
  • 显式等待
    locator = (By.XPATH, "//select/option")
    WebDriverWait(driver, 10, 0.5).until(EC.presence_of_element_located(locator))
    # 等待判断准确,不会浪费多余的等待时间,在实际使用中可以提高执行效率
    

5.3.1 等待方法

  • EC.presence_of_element_located(locator)
    • 等待locator指定的元素出现,也就是HTML文档中建立起了这个元素
  • EC.visibility_of_element_located(locator)
    • 等待locator指定的元素可见
  • EC.element_to_be_clickable(locator)
    • 等待locator指定的元素可以被点击
  • EC.element_to_be_selected(locator)
    • 等待locator指定的元素可以被选择
    • 可以被选择的元素一般是<select>中的选项<option>、输入的多选框<input type="checkbox">、输入的单选框<input type="radio">
  • EC.text_to_be_present_in_element(locator, text)
    • 等待locator指定的元素的文本中包含指定的text文本
    locator = (By.ID, "msg")
    WebDriverWait(driver, 10, 0,5).until(EC.text_to_be_present_in_element(locator, "品"))
    
    # 等待<span id="msg">...</span>元素中的文本包含“品”,
    # 由于在<option>出现后设置文本时“品牌”,因此爬虫程序可以爬取到手机品牌数据
    

第七章 读取文档

7.1 文档编码

纯文本信息
HTML展示
纯文本文件
图像文件
视频文件
  • 共同点:所有信息和文档都是由0和1编码而成
  • 不同点:面向用户的转换方式不同

完整代码:

import urllib
from urllib.request import urlopen

headers = {
    "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"
    }

req = urllib.request.Request("http://www.pythonscraping.com/pages/warandpeace/chapter1-ru.txt", headers=headers)
resp = urllib.request.urlopen(req, timeout=10)
html = resp.read()

rutxt = html.decode('utf-8')
print(rutxt)

检索该文本文档的编码方法

import chardet
type = chardet.detect(html)
rutxt = html.decode(type["encoding"])

网页中有注明编码方式,查询<meta>标签
<meta charset="utf-8">

7.2 不同格式文档的读取和存储

CSVPDFDOCX
格式特点以纯文本形式存储表格数据(数字和文本)以PostScript语言图像模型为基础,是跨平台(应用程序、操作系统、硬件无关)支持多媒体集成文件类XML格式标准
读取csv.Reader()、csv.DictReader()方法,和引用io里面的StringIO()安装pdfminer3kfrom zipfile import ZipFile、from io import BytesIO、from bs4 import BeautitulSoup
存储csv.writer()不关注内容的转存,f.write(data)

7.3 PDF读取和存储

思路:PDF读成字符串,然后用StingIO转换成文件对象

# 获取文档对象
fp = open("selenium_documentation_o.pdf", "rb")

# 创建一个与文档关联的解释器
parser = PDFParser(fp)

# PDF文档的对象
doc = PDFDocument()

# 链接解释器和文档对象
parser.set_document(doc)
doc.set_parser(parser)

# 初始化文档
doc.initialize("")

在这里插入图片描述

7.3.1 读取pdf

import urllib
from urllib.request import urlopen
from io import StringIO
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from io import open

def readPDF(pdfFile):
    rsrcmgr = PDFReasourceManager() # 创建PDF资源管理对象
    retstr = StringIO() # StingIO转换成文件对象
    laparams = LAParams()   # 布局参数分析器
    device = TextConverter(rsrcmgr, retstr, laparams=laparams)  # 创建设备对象
    process_pdf(rsrcmgr, device, pdfFile)   # PDF页面解释器,等同于PDFPage.get_pages
    
    device.close()
    
    content = retstr.getvalue()
    retstr.close()
    return content
7.3.1.1下载服务器pdf文件
req = urllib.request.Request("http://pythonscraping.com/pages/warandpeace/chapter1.pdf",headers=headers)
pdfFile = urllib.request.urlopen(req, timeout=10)

outputString = readPDF(pdfFile)
print(outputString)
pdfFile.close()
7.3.1.2 打开本地PDF文件
pdfFile = open("F:\First Home work.pdf", "rb")

outputString = readPDF(pdfFile)
print(outputString)
pdfFile.close()

7.3.2 PDF文件的存储

req = urllib.request.Request("http://pythonscraping.com/pages/warandpeace/chapter1.pdf", headers=headers)
pdfFile = urllib.request.urlopen(req, timeout=10)

data = pdfFile.read()
# 存储PDF文件
pdfStoreFile = "F:\warandpeace_chapter1.pdf"

with open(pdfStoreFile, 'wb+') as f:
    f.write(data)

7.3.3 网页信息转存为pdf

from fpdf import FPDF
from fpdf import HTMLMixin

class HTML2PDF(FPDF,HTMLMixin):
    pass
def html2pdf():
    html = '''<h1 align ="center">PyFPDF HTML Demo</h1>
    <p>This is regular text</p>
    <p>You can also <b>bold</b>, <i>italicize</i> or <u>underline</u></p>
    '''
    pdf = HTML2PDF()
    pdf.add_page() # 加一页
    pdf.write_html(html)
    pdf.output('html2pdf.pdf')

html2pdf()

7.4 读取.docx文件的正文内容

  1. 从.docx文件读取XML
  2. 从XML中找到包含在<w:t>标签的正文的信息
远程打开docx文件
封装为二进制文件对象
解压
读取解压文件获得XML信息
from zipfile import ZipFile
from urllib.request import urlopen
from io import BytesIO
from bs4 import BeautifulSoup

wordFile = urlopen("http://pythonscraping.com/pages/AWordDocument.docx").read()
wordFile = BytesIO(workFile)
xml_content = document.read("word/document.xml") # 正文内容隐藏在xml里
print(xml_content.decode('utf-8'))

# <w:t>非标准标签,需要解析器xml解析
wordObj = BeautifulSoup(xml_content.decode('utf-8'), "xml")
textString = wordObj.findAll("w:t")    # 找到包含在<w:t>标签的正文
for textElem in textString:
    style = textElem.parent.parent.find('w:pStyle')
    if style is not None and style['w:val']=="Title":
        print("Title is :{}".format(textElem.text)) # 按不同要求单独打印标题
    else:
        print(textElem.txt)
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值