学习python爬虫的一些基础

学习python爬虫的一些基础

1.浏览器

一个网页加载的过程

1.服务器端渲染

​ html的页面的内容和数据在服务器进行配合。

​ 在浏览器端看到的页面源代码中,有需要的内容

2.客户端渲染(浏览器)

​ html的内容和数据进行融合是发生在浏览器。(通过浏览器和服务端端交互进行渲染,如:通过js代码发送ajax请求),通过浏览器的devtools的network可以看到请求交互过程

​ 在解析过程中,devtools中element不一定准确,内容有可能是经过js处理后的,要以页面源代码或response.text为准来解析数据

2.Requests

爬虫的本质就是用程序模拟浏览器上的请求。

爬虫程序不是人,很有可能生成病毒,爬取过程中不应该去触碰个人隐私信息。在浏览器看不到的数据,爬虫是无法爬取的。

requests模块式python的一个非常完善的第三方模块,专门用来模拟浏览器进行网络请求的发送。

requests常用的请求方式,get、post

get、post是http的请求方式,只需要根据抓包里面的状况去选择具体用那种方式去请求。

get和post的请求方式不同

get的请求参数最终被放在url中,params和url传参二选一

query string parmas

resp = requests.get('www.baidu.com', params={
    "ie":'utf8',
    'wd':'周杰伦'
})
resp = requests.get('www.baidu.com?ie=utf8&wd=周杰伦)

post的请求参数放在请求body中。

post 常规请求参数 FormData, Request Payload

requests.post('url', data={字典})
requests.post('url',json={字典})
requests.post(url, data=json.dumps{字典}, headers={
    "content-Type":"application/json;charset=utf-8"
})

状态码(http状态码)

200 系列 指当前本次和服务器通信ok

300 系列 指重定向

​ 写爬虫的时候基本上不用管302,因为requests可以自动重定向到新的页面

400 系列

404 url不存在,在服务器上无法响应该内容

403 被服务器拦截,访问权限问题

500 系列 表示服务器内部出现错误

​ 如果浏览器正常,但是爬虫程序的时候出现500错误,基本上就是参数错误,让服务器无法正常 工作。

timeout, 服务器连接失败 多种因素引起的,最好的解决办法就是:

for i in range(5):
    try:
        发送请求
        break
    except Exception as e:
    	print(e)

3.数据解析

html

​ re --> .*? 想拿到html中获取js的一部分代码(字符串)

​ xpath --> 用来解析常规的html结构

from lxml import etree
tree = etree.HTML(resp.text)
ret = tree.xpah('//div/fd/')
# etree的xpath默认返回的是列表。
if ret:
    ret[0]
else:
    xxx

​ bs4 --> 解析xml、 svg的时候

find()
findall()

json

​ resp.json()

​ json.loads(resp.text)

​ 如果遇到反爬,就可能拿到的内容和抓包工具不一致,一般先打印resp.text,确定返回的内容是json格式,才开始转化

jsonp

4.反爬(header)

​ 请求头:

​ User-Agent 用户发送请求的设备

​ Cookie 服务器记录在浏览器上的一个字符串,保存在本地,记录用户信息,再次发送请求的时候自动携带,作用是和服务器之间保持会话。session 服务器端对应的内容。因为http请求是一个无状态请求,无法像socket一样保持会话。

							1. 可以直接从浏览器抓包中复制(某些网站可以)
							2. 用requests.session()来保持会话, requests.session()可以处理set-cookie的内容,但不能处理javascript处理的cookies的内容。如果网站用js维护cookies,就需要自己通过带来来处理逻辑。

​ Referer 检测上一页页面的url是什么,一般直接复制粘贴就可以

​ 网页自己添加的参数 一般都需要手工逆向来处理

请求头一般通过测试来选择要添加的内容。一般加user-anagent。

​ 响应头:

​ Location 302 重定向地址

​ Set-Cookie session自动维护

​ 网页自己添加的参数 一般情况网站是没有的,除非是特殊网站

session的使用

session = requests.session()
session.headers={}
session.cookie = {}
session.get()
session.post()

5.多任务异步爬虫 (多线程、多进程、协程)

​ 进程是资源单位,进程之间是隔离开的

​ 全局变量 a

​ p1 = Process()

​ p2 = Process()

在p1中修改a的值,在p2中没有任何变更,因为两个进程是隔离开的,p1,p2相当于两个程序

Queue队列或redis 两个进程之间的数据交换

协程

# 爬虫案例
import asyncio
import aiohttp
from lxml import etree
url = "17k.com/"
async def download_one(url):
    async with aiohttp.ClientSession() as session:
        # requsets.sesson()
        async with session.get(url) as resp:
            page_source = await resp.text()
            tree = etree.HTML(page_source) # 不是io操作需要计算,不需要挂起
            print(tree.xpah("//table//text()"))
		
async def main():
    tasks = []
    for i in range(1.6):
        url = "https://www.17d.com/all/book/2_0_0_0_0_0_0_{i}.html"
        # 每一个url对应一个任务
        task = asyncio.create_task(download_one(url))
        tasks.append(task)
    await asyncio.wait(tasks)
 
if__name__ == '__main__':
    asyncio.run() # 相当于
    event_loop = asynico.get_event_loop()
    event_loop.run_until_complete(main())

面临的每一个网站的设计思路和反爬思路不一样,在实际爬取过程中,根据不同的网站,来灵活运用,见招拆招。

6.数据存储(Mongodb,Mysql, Redis,Excel)

csv 本质就是一个文本文件

写操作
数据之间用,分隔
f = open("data.csv", mode='w', encoding='utf-8')
f.write("1")
f.write(",")
f.write("张伟")
f.write(",")
f.write("5000")
f.write("\n")"
用pandas读取
import pandas

r = pandas.read_csv("data.csv", sep=",", header=None)  # sep 分隔符号
print(r)
输出为excel
r.to_excel('data.xlsx', header=False, index=False)

Mysql 关系型数据库, 以表格的形式进行存储,关系型数据库依赖于表格,表格与表格之间可以建立关系,通过主外键关系建立关联,主键唯一的表示一条数据,将主键作为另一张表的外键。

关系有: 一对一关系;一对多关系;多对多关系

create table 表名(
字段 类型 约束
...)
-- 一般可以通过navicat工具来创建表
# 增加数据
insert into 表(字段1, 字段2, 字段3...) values(1, 值2, 值3...)
还有一种方式insert into 表 values(1, 值2, 值3...) 一般不用这种方式,容易出现混乱
# 修改数据
update 表 set 字段=值, 字段= 值 where id = 1
# 删除数据
delete from 表 where 条件
# 查询数据
select * from 表 where 条件;

python 操作数据库

import pymysql
from pymysql.cursors import DictCursor

# 1.创建连接
conn = pymysql.connect(
    user='root',
    password=,
    host='127.0.0.1',
    database='student',
    port=3306,
    charset="utf8mb4",
)
#   2.创建游标
# cursor = conn.cursor()  # 普通游标, 数据获取后是一个元组
try:
    cursor = conn.cursor(DictCursor)  # 字典游标,数据获取后是一个字典
    sql = 'select * from user'
    cursor.execute(sql)
    cursor.fetchone()  # 获取一条数据
    cursor.fetchall()  # 获取所有数据
    cursor.fetchmany(size=None)  # 获取部分数据
    
    # 3. 新增数据
    sql = 'insert into 表名(键1,键2,键3)values (值1, 值2, 值3)'
    # 提交事务
    cursor.execute(sql)
    # 如果不报错
    conn.commit()  # 数据增加后提交
except Exception as e:
    print(e)
    # 如果报错
    conn.rollback()  # 回滚
finally:
    conn.close()

reids 是以key:value的形式存储数据

​ key -> 数据(单一字符串, 列表, 字典,set)

​ 数据类型和key

​ 常用的数据类型:

1.string

​ set key value

​ get key 查看一条数据

​ incr key 让该key对应的数据自增(原子性,安全)

​ incrby key count 让该key对应的value自增 count

​ type key 查看数据类型

set name 张三 # 添加数据name=张三
get name # 查看数据 张三
set age 10 
get age  # 10
incr age # 11
get age	#11
incrby age 5 # 16
  1. hash

    哈希,相当于字典,常见操作

    hset key k1 v1 将k1, v1存在key上

    hget key k1 将key上的k1提取

    hmset key k1 v1 k2 v2 k3 v3 一次性将多个k,v存储在key

    hmget key k1 k2 一次性将key中的k1 k2 提取出来

    hgetall key 一次性将key中的内容全部提取出来

    hkeys key 将key中所有的k全部提取

    kvals key 将key中的所有v提取

    HMSET stu id 1 name 张三 age 18
    HNGET stu name age # 张三 18
    HMGETALL stu # id 1 name 张三 age 18
    HEYS stu # id name age
    KVALS stu	# 1 张三 18
    
  2. list 列表,底层是要给双向列表,可以从左或从右插入

    常见操作

    lpush key 数据1 数据2 数据3 从左边插入数据

    rpush key 数据1 数据2 数据3 从右边插入数据

    lrange key start stop # 从start到stop提取数据

    llen key 返回key列表长度

    lpop key 从左边删除一个数据并返回 被删除的元素

    rpop key 从右边删除一个数据并返回被删除的元素

    lpush classname 123班
    lrange classname 0 -1 #   1班 2班 3班
    rpush classname 4班
    lrange ban -1 # 1班 2班 3班 4班
    lpop classname # 1班
    rpop classname # 4班
    llen classname # 3
    
  3. set

    set是无需的超大集合,无需不重复

    常见操作

    sadd key 值 向集合内存入数据

    smembers key 查看集合内所有元素

    scard key 常看集合中元素的个数

    sismember key val 查看集合中时候包含val这个元素

    sunion key1 key2 key1和key2 两个集合的并集

    sdiff key1 key2 key1和key2两个集合的差集, 在key1集合中,但不在key2集合中

    sinter key1 key 2 计算交集, 在key1和key2中都出现了

    spop key 随机中key中删除一个数据

    srandmember key count 随机从key中查询count个数据

    sadd start 姜维 李明 王红 张强 # 4
    add start 李明  # 0 重复的数据是无法存储进去的
    semebers start # 姜维 李明 王红 张强
    sismember start 李明 # 李明在不在集合start中在就返回1 不在返回0
    

5.zset 有序集合,有序集合的元素也具有唯一性,并且存储的数据也是redis最基础的string数据,但是在存储数据的同时还增加了一个score表示分值, redis就是通过这个score作为排序的规则

常用操作

zadd key s1 m1 s2 m2 # 在向key中存入m1 m2 分数分别是 s1 s2

zrange key start stop 【withsores】 # 查看从start到stop中的所有数据【是否要分数】

zrevrange key start stop 倒叙查看start到stop的数据

zcard key 查看zset数据元素的个数

zcount key min max 查看分数在min和max之间的数据量

zincrby key score member 将key中member的分值score

zscore key m 查看key中m的分值

zadd familay 1 爸爸 2 儿子 3 女儿
zrange family 0 -1 withscores # 正序查看
zrevarange family 0 -1 withscores # 倒叙查看
zincrby family 5 女儿 # 给女儿加5分
zadd family 10 儿子 # 将儿子的分数改为100分
zscore family 爸爸 # 查看爸爸的分值
zcard familay # 查看整个家庭的数据个数

所有的set集合基本都是无序的,zset的底层是给每一个数据增加一个分值,通过分值进行排列

python操作redis

import redis

conn = redis.Redis(
    host='localhost',
    port=6379,
    db=4
)
conn.set('myname', "joy")
r = conn.get('myname')
print(r)    # b'joy'

7.面向对象(基础)

核心:编程实现的转变。

面向过程的爬虫: (函数的执行)

1. 获取页面代码
2. 解析页面代码
3. 存储数据

面向对象的爬虫:通过操作对象,实现爬虫。 (类的实现,通过属性的赋值和方法的实现爬虫)

面向对象的三大特性:封装、继承、多态

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值