学习总结

### 本周学习任务

```
1. selenium 模拟爬取数据及自动化测试(重点)
2. scrapy爬虫
3. 反爬虫技术(重点)
4. 广度比深度重要,扩展知识面.
```

### js混淆

使用反混淆得到反混淆的js代码

把js代码替换成python代码

使用正则, xpath, css解析html文件

### CSS选择器

- CSS 指层叠样式表 (**C**ascading **S**tyle **S**heets)
- 样式定义**如何显示** HTML 元素
- 样式通常存储在**样式表**- 把样式添加到 HTML 4.0 中,是为了**解决内容与表现分离的问题**
- **外部样式表**可以极大提高工作效率
- 外部样式表通常存储在 **CSS 文件**- 多个样式定义可**层叠**为一

### css:after 选择器

:after 选择器向选定的元素之后插入内容。

使用[content](http://www.runoob.com/cssref/pr-gen-content.html) 属性来指定要插入的内容。

```css
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> 
<title>菜鸟教程(runoob.com)</title> 
<style>
p:after
{ 
    content:"- Remember this";
    background-color:yellow;
    color:red;
    font-weight:bold;
}
</style>
</head>

<body>
<p>My name is Donald</p>
<p>I live in Ducksburg</p>

<p><b>注意:</b>:after作用于IE8 以及更早版本的浏览器,DOCTYPE 必须已经声明.</p>

</body>
</html>
```

结果:

```css
My name is Donald- Remember this

I live in Ducksburg- Remember this

注意::after作用于IE8 以及更早版本的浏览器,DOCTYPE 必须已经声明.- Remember this
```



### css:before 选择器

before 选择器向选定的元素前插入内容。

使用[content](http://www.runoob.com/cssref/pr-gen-content.html) 属性来指定要插入的内容。

```css
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> 
<title>菜鸟教程(runoob.com)</title> 
<style>
p:before
{ 
    content:"Read this -";
    background-color:yellow;
    color:red;
    font-weight:bold;
}
</style>
</head>

<body>
<p>My name is Donald</p>
<p>I live in Ducksburg</p>

<p><b>注意:</b>  :before 作用于 IE8, DOCTYPE 必须已经声明.</p>

</body>
</html>
```

结果:

```css
Read this -My name is Donald

Read this -I live in Ducksburg

Read this -注意: :before 作用于 IE8, DOCTYPE 必须已经声明.
```

### nth-child() 选择器

nth-child(n) 选择器匹配父元素中的第 n 个子元素,元素类型没有限制。

*n* 可以是一个数字,一个关键字,或者一个公式。

```css
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> 
<title>菜鸟教程(runoob.com)</title> 
<style> 
p:nth-child(odd)
{
    background:#ff0000;
}
p:nth-child(even)
{
    background:#0000ff;
}
</style>
</head>
<body>

<h1>This is a heading</h1>
<p>The first paragraph.</p>
<p>The second paragraph.</p>
<p>The third paragraph.</p>

<p><b>注意:</b> Internet Explorer 8 and以及更早版本的浏览器 :nth-child()选择器.</p>

</body>
</html>
```

结果:![img](file:///C:UsersAdministratorAppDataRoamingTencentUsers306675036QQWinTempRichOleOK%0$9KEROFG1KOCF_AUDF2.png) 



### 爬虫三大块

1. 抓取网页(requests(urllib), scrapy,  cookie, ajax,字体加密)
2. 解析(网页结构复杂)
3. 存储(监控变化:md5, sha等信息摘要)

### 多线程

  从计算机硬件角度:

 计算机的核心是CPU,承担了所有的计算机任务.

  一个CPU,在一个时间切片里只能运行一个程序.

从操作系统的角度:

进程和线程,都是一种CPU的执行单元.

进程:表示一个程序的上下文执行活动,(打开, 执行, 保存).

线程:进程执行程序时候的最小调度到位(执行a, 执行b...).

一个程序至少有一个进程, 一个进程至少有一个线程.

多进程/多线程:

表示可以同时执行多个任务,进程和线程的调度是由操作系统自动完成.

进程:每个进程都有自己独立的内存空间,不同进程之间的内存空间不共享.

进程之间的通信有操作系统传递,导致通讯效率低,切换开销大.

### 互斥锁

线程: 一个进程可以有多个线程,所有先后线程共享进程得内存空间,通讯效率高,切换开销小.

共享意味着竞争,导致数据不安全,为了保护内存空间的数据安全,引入"互斥锁".

一个线程在访问内存空间的时候,其他线程不允许访问,必须等待之前的线程访问结束,才能使用这个内存空间.

互斥锁: 一种安全有序的让多个线程访问内存空间的机制.

### GIL

​    GIL 全局解释器锁: 线程的执行权限,在Python的进程只有一个GIL.

一个线程需要执行任务,必须获取GIL.

好处:直接杜绝了多个线程访问内存空间的安全问题.

坏处: Python的多线程不是真的多线程,不能充分利用多核CPU的资源.但是在I/O阻塞的时候,解释器会释放GIL.

### IO

IO在计算机中指Input/Output,也就是输入和输出。

由于程序和运行时数据是在内存中驻留,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘、网络等,就需要IO接口。 

第一种是CPU等着,也就是程序暂停执行后续代码,等100M的数据在10秒后写入磁盘,再接着往下执行,这种模式称为同步IO;

另一种方法是CPU不等待,只是告诉磁盘,“您老慢慢写,不着急,我接着干别的事去了”,于是,后续代码可以立刻接着执行,这种模式称为异步IO。

同步和异步的区别就在于是否等待IO执行的结果。好比你去麦当劳点餐,你说“来个汉堡”,服务员告诉你,对不起,汉堡要现做,需要等5分钟,于是你站在收银台前面等了5分钟,拿到汉堡再去逛商场,这是同步IO。

## selenium(自动化测试)

### 必写代码

```python
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
options = Options()
browser = webdriver.Firefox(executable_path='F:/mo_ni_gong_ju_pa_chong/geckodriver.exe', firefox_options=options)
```

### 常用语法

​    模拟打开一个网页    

​    

```python
browser.get('http://www.baidu.com')
```



​    关闭浏览器

​    

```python
browser.close()
```



​    最大化窗口

- ```python
  browser.maximize_window()
  ```

  查找需要内容

- ```python
  browser.find_element_by_xpath
  browser.find_element_by_id
  
  # a标签里的text文件才能用此函数
  article = browser.find_element_by_link_text('Log In')
  # 等等等等
  ```

  点击

- ```python
  login = browser.find_element_by_xpath('//button')
  点击login
  login.click()
  ```

  输入

- ```python
  content = browser.find_element_by_id('content')
  content.send_keys('老子就是想请假')
  ```

###模拟鼠标放上(ActionChains:动作链)



- ```python
  from selenium import webdriver
  from selenium.webdriver.firefox.options import Options as FOptions
  from selenium.webdriver.common.action_chains import ActionChains
  
  options = FOptions()
  browser = webdriver.Firefox(executable_path="F:/mo_ni_gong_ju_pa_chong/geckodriver.exe", firefox_options=options)
  
  browser.get('http://example.webscraping.com')
  # a标签里的text文件才能用此函数
  article = browser.find_element_by_link_text('Log In')
  # 产生一个移动鼠标的动作链,移动到Log In元素(article) perform 执行前面的动作链
  ActionChains(browser).move_to_element(article).perform()
  menu = browser.find_element_by_xpath('//a[@href="/places/default/user/register?_next=/places/default/index"]')
  menu.click()
  
  ```

  打印网页源码

- ```python
  browser.page_source
  ```

  执行javescript语句

- ```python
  browser.get("www.baidu.com")
  time.sleep(3)
  # 滚动到页面底部
  browser.execute_script("window.scrollTo(0,document.body.scrollHeight)")
  ```

  切换到新窗口

- ```python
  browser.get("http://www.baidu.com")
  handles = browser.window_handles
  browser.switch_to.window(handles[-1])
  ```

  打印弹窗中的内容

- ```python
  t = browser.switch_to_alert()
  print(t.text)
  ```

## 元素拖拽





- drag_and_drop()方法使用,drag_and_drop()方法涉及到参数传递,一个是要拖拽元素的起点,一个是要拖拽元素的终点 

- ```python
  browser.get("http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable")
  browser.switch_to.frame('iframeResult')
  # 起点
  source = browser.find_element_by_id('draggable')
  # 终点
  target = browser.find_element_by_id('droppable')
  
  actions = ActionChains(browser)
  actions.drag_and_drop(source,target)
  
  # 执行以上动作链
  actions.perform()
  ```

### <frame> 标签定义 frameset 中的一个特定的窗口(框架)



```python
browser.switch_to.frame('iframeResult')
```

# Scrapy(爬虫)

### 安装scrapy

```python
pip install scrapy
```

windows下报错没有c++包,需要到https://www.lfd.uci.edu/~gohlke/pythonlibs/ 下载跟电脑相对应的版本Twisted.

twisted是一个异步网络框架.

创建scrapy爬虫项目

```python
scrapy startproject genera_scrapy  # CountrySpider 项目名
```

![1545882242056](C:UsersADMINI~1AppDataLocalTemp1545882242056.png)

创建爬虫文件

```python
scrapy genspider CountrySpider example.com    # CountrySpider 爬虫文件名)
```

![1545882630742](C:UsersADMINI~1AppDataLocalTemp1545882630742.png)

配置settings文件

```python
ROBOTSTXT_OBEY = False        # 把默认Ture 改为False

# ITEM_PIPELINES 释放开
ITEM_PIPELINES = {
   'genera_scrapy.pipelines.GeneraScrapyPipeline': 300,
}
```

简单的爬虫代码

```python
import scrapy


class CountryspiderSpider(scrapy.Spider):
    name = 'CountrySpider'
    allowed_domains = ['webscraping.com']
    start_urls = ['http://example.webscraping.com/places/default/view/China-47/']

    def parse(self, response):
        print(response.body)
        item = {}
        item['name'] = response.css('tr#places_country__rowtd.w2p_fw::text').extract_first()
        item['population'] = response.css('tr#places_population__rowtd.w2p_fw::text').extract_first()
        yield item

```

存入sqlite3数据库

```python
import sqlite3


class GeneraScrapyPipeline(object):
    # 系统要求的处理item的函数, 不能随意写
    def process_item(self, item, spider):
        print(item)
        conn = sqlite3.connect("country.db")
        cursor = conn.cursor()
        save_dic = {"name": item['name'], "population": item['population']}

        sql_insert = """insert into country values(?,?)"""
        param = (item['name'], item['population'])
        cursor.execute(sql_insert, param)
        conn.commit()
        return item
```

### sqlite3 sql语句操作

下载安装sqlite,添加到环境变量中

### 插入数据

- 插入一条数据

```python
INSERT INTO table_name ( field1, field2,...fieldN )
                       VALUES
                       ( value1, value2,...valueN );
```

- 插入多条数据

```
INSERT INTO table_name  (field1, field2,...fieldN)  VALUES  (valueA1,valueA2,...valueAN),(valueB1,valueB2,...valueBN),(valueC1,valueC2,...valueCN)......;
```

### 查询数据

- 以下为在MySQL数据库中查询数据通用的 SELECT 语法: 

```
SELECT column_name,column_name
FROM table_name
[WHERE Clause]
[LIMIT N][ OFFSET M]
```

- 以下实例将返回数据表 runoob_tbl 的所有记录 

```
select * from runoob_tbl;
```

#### where 条件查询

```
SELECT field1, field2,...fieldN FROM table_name1, table_name2...
[WHERE condition1 [AND [OR]] condition2.....
```

- 以下实例将读取 runoob_tbl 表中 runoob_author 字段值为 Sanjay 的所有记录: 

```
SELECT * from runoob_tbl WHERE runoob_author='菜鸟教程';
```

- MySQL 的 WHERE 子句的字符串比较是不区分大小写的。 你可以使用 BINARY 关键字来设定 WHERE 子句的字符串比较是区分大小写的。 

```
mysql> SELECT * from runoob_tbl WHERE BINARY runoob_author='RUNOOB.COM';
```

### 更新数据

- 以下是 UPDATE 命令修改 MySQL 数据表数据的通用 SQL 语法: 

```
UPDATE table_name SET field1=new-value1, field2=new-value2
[WHERE Clause]
```

- 将 id 为 5 的手机号改为默认的 - 

```python
update students settel=default where id=5;
```

- 将所有人的年龄增加 1 

```
update students set age=age+1;
```

- 将手机号为 13288097888 的姓名改为 "小明", 年龄改为 19: 

```
update students setname="小明", age=19 where tel="13288097888";
```

- 以下实例将更新 runoob_id 为 3 的runoob_title 字段值的 "C++" 替换为 "Python": 

```
UPDATE runoob_tbl SET runoob_title = REPLACE(runoob_title, 'C++', 'Python') where runoob_id = 3;
```



### 删除数据

- 以下是 SQL DELETE 语句从 MySQL 数据表中删除数据的通用语法: 

```
DELETE FROM table_name [WHERE Clause]
```

- delete 语句用于删除表中的数据, 基本用法为: 

> - 删除 id 为 3 的行: delete from students where id=3; 
> - 删除所有年龄小于 21 岁的数据: delete from students where age<20; 
> - 删除表中的所有数据: delete from students; 

- delete,drop,truncate 都有删除表的作用,区别在于: 

> - 1、delete 和 truncate 仅仅删除表数据,drop 连表数据和表结构一起删除,打个比方,delete 是单杀,truncate 是团灭,drop 是把电脑摔了。 
> - 2、delete 是 DML 语句,操作完以后如果没有不想提交事务还可以回滚,truncate 和 drop 是 DDL  语句,操作完马上生效,不能回滚,打个比方,delete 是发微信说分手,后悔还可以撤回,truncate 和 drop  是直接扇耳光说滚,不能反悔。 
> - 3、执行的速度上,**drop>truncate>delete**,打个比方,drop 是神舟火箭,truncate 是和谐号动车,delete 是自行车。 

### 模糊查询

- like 匹配/模糊匹配,会与 % 和 _ 结合使用 。

```python
'%a'     //以a结尾的数据
'a%'     //以a开头的数据
'%a%'    //含有a的数据
'_a_'    //三位且中间字母是a的
'_a'     //两位且结尾字母是a的
'a_'     //两位且开头字母是a的
```

- 查询以 java 字段开头的信息。 

> ```
> SELECT * FROM position WHERE name LIKE 'java%';
> ```

- 查询包含 java 字段的信息。 

> ```
> SELECT * FROM position WHERE name LIKE '%java%';
> ```

- 查询以 java 字段结尾的信息。 

> ```
> SELECT * FROM position WHERE name LIKE '%java';
> ```

### 连接两个以上的 SELECT 语句的结果组合到一个结果集合中

- **UNION 语句**:用于将不同表中相同列中查询的数据展示出来;(不包括重复数据)
- **UNION ALL 语句**:用于将不同表中相同列中查询的数据展示出来;(包括重复数据)使用形式如下:

```python
SELECT 列名称 FROM 表名称 UNION SELECT 列名称 FROM 表名称 ORDER BY 列名称;
SELECT 列名称 FROM 表名称 UNION ALL SELECT 列名称 FROM 表名称 ORDER BY 列名称;
```

### 排序 (默认升序, ASC升序, DESC降序)

- SELECT * from runoob_tbl ORDER BY submission_date ASC; 
- SELECT * from runoob_tbl ORDER BY submission_date DESC; 
原文地址:https://www.cnblogs.com/liangliangzz/p/10221944.html