爬虫学习笔记

目录

一、 初识爬虫

1. 简单的爬虫

2.  web请求

3. http协议

4. requests入门

二、数据解析与提取

1. 概述

2. Regular Expression 正则表达式

3. re模块

4. 豆瓣电影练习

5. 电影天堂练习

6. bs4 北京新发地、热搜榜

7. 抓取图库图片

8. Xpath语法

9. xpath猪八戒网练习

三. request模块进阶

1. 模拟用户登录 cookie

2. 防盗链处理

3. 代理

4. 爬取网易云音乐评论

四. 多线程

1. 多线程的两种写法

2. 多进程 

3. 线程池和进程池

4. 抓取新发地菜价

5. 多任务异步协程

6. aiohttp模块

7. 抓取一本电子书

8. 抓取一部视频

五、selenium

1. 拉钩网

2. 页面切换

3. 无头浏览器

4. 破解验证码并登录

5. 12306

六. 数据存储

1. json

json的保存

json的读取

2. csv

3. mysql


一、 初识爬虫

1. 简单的爬虫

from urllib.request import urlopen

url = "http://www.baidu.com/"
resp = urlopen(url)
message = resp.read().decode("utf-8")

print(message)

with open("my_spyder.html", mode="w", encoding="utf-8") as f:
    f.write(message)
print("over!")

open的时候要指定encoding是utf-8,windows系统默认gbk,会乱码。

baidu网址输入的时候注意是http,没有s。

2.  web请求

1.服务器渲染:再服务器那边直接把数据和html整合在一起,统一返回给浏览器

  再页面源代码中能看到数据

2.客户端渲染:第一次请求html骨架,第二次请求数据。进行数据展示

  在页面源代码中看不到数据

熟练使用浏览器抓包工具 f12里看

3. http协议

请求:

  • 请求行:包括请求方式,请求url地址,协议
  • 请求头:放一些服务器要使用的附加信息
  • 请求体:一般放一些请求参数

响应:

  • 状态行:协议 状态码
  • 响应头:放一些客户端要使用的一些附加信息
  • 响应体:服务器返回的真正客户端要用的内容

请求头重最常见的一些重要内容:

  • User-Agent:请求载体的身份识别(用什么发送的请求)
  • Referer:防盗链(这次请求从哪个页面来?反爬用到)
  • cookie:本地字符串数据信息(用户登录信息,反爬的token)

响应头重一些重要的内容:

  • cookie:本地字符串数据信息
  • 各种神奇的莫名其妙的字符串(需要经验,一般都是token字样,防止各种攻击和反爬)

请求方式:

  • GET: 显式提交
  • POST: 隐式提交

4. requests入门

import requests

url = "https://www.sogou.com/web?query=周杰伦"
resp = requests.get(url)

print(resp)

此处用vscode一直报错无法找到requests,换用pycharm可以使用,输出为200.

不知道为什么。

print(resp.text)

输出页面后被拦截,因为被检测到是自动程序发出的。

打开指定页面,审查元素找到User-Agent复制过来。用来伪装成正常访问请求。

url = "https://www.sogou.com/web?query=周杰伦"

dic = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"
}
resp = requests.get(url, headers=dic)

修改请求头。

审查元素可以看到用的是post还是get。

百度翻译使用的是get。使用英文输入法输入单词,在network中监视,找到sug,发现翻译是通过https://fanyi.baidu.com/sug实现,并且使用的是GET。

找到form-data为输入的表单信息,因此只要替换form-data就可以实现自定义输入。

import  requests

url = "https://fanyi.baidu.com/sug"

s = input("输入需要翻译的英文单词:")
dat = {
    "kw": s
}

# 发送post请求,发送数据必须放在字典中
resp = requests.post(url, data=dat)
print(resp.json()) # 将服务器返回的内容直接返回为json() =>字典

直接resp.text会出现乱码,用json可以解释成字典。

请求url太长可以考虑封装

这些内容都包含在url里。

url = "https://movie.douban.com/typerank?type_name=%E5%96%9C%E5%89%A7&type=24&interval_id=100:90&action="

 重新封装

url = "https://movie.douban.com/j/chart/top-list"

# 重新封装参数
param = {
    "type": "24",
    "interval_id": "100:90",
    "action": "",
    "start": 0,
    "limit": 20
}

requests.get(url=url, params=param)
print(resp.text)

如果发现异常,说明可能被挡了,优先考虑user-agent。添加后就可以了

import requests

url = "https://movie.douban.com/j/chart/top_list"


# 重新封装参数
param = {
    "type": "24",
    "interval_id": "100:90",
    "action": "",
    "start": 0,
    "limit": 20
}

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"
}

resp = requests.get(url=url, params=param, headers=headers)

print(resp.json())


二、数据解析与提取

1. 概述

本课程提供三种解析方式:

  • re解析,运行最快
  • bs4解析,最简单,但效率不高
  • xpath解析,比较流行,写起来简单

2. Regular Expression 正则表达式

上手难度高。速度快,效率高,准确性高。

正则的语法:使用元字符进行排列组合用来匹配字符串

语法测试网站:开源中国-正则表达式测试

常用元字符

每个元字符默认只匹配一个字符串。

.      匹配除换行符以外的任意字符

\w   匹配字母数字下划线

\s    匹配任意空白符

\d    匹配数字

\n    匹配一个换行符

\t    匹配一个制表符

^    匹配字符串的开始(开始的时候必须符合要求

$    匹配字符串的结尾(结尾的时候除了要求,不能有别的

\W  匹配非字母数字下划线

\D   匹配非数字

\S    匹配非空白符

a|b   匹配字符a或字符b

()     匹配括号内的表达式,也表示一个组

[...]   匹配字符组中的字符

[^...]  匹配除了字符组中字符的所有字符

量词:

控制前面的元字符出现的次数

*       重复零次或多次

+      重复一次或更多次

?     重复零次或一次

{n}    重复n次

{n,}    重复n次或更多次

{n,m}  重复n到m次

.*       贪婪匹配(尽可能多的匹配)

.*?     惰性匹配(尽可能少的,可以理解为就近匹配)

3. re模块

# findall: 匹配字符串中所有的符合正则的内容,返回的是列表    不常用
lst = re.findall(r"\d+", "我的电话号码是:123, 我朋友的电话:456")
print(lst)

# finditer: 匹配字符串中所有的内容,返回的是迭代器
it = re.finditer(r"\d+", "我的电话号码是:123, 我朋友的电话:456")
print(it)
for i in it:
    print(i.group())

# search,全文匹配,找到一个结果就返回 返回的是match对象,拿数据需要.group()
s = re.search(r"\d+", "我的电话号码是:123, 我朋友的电话:456")
print(s.group())

# match是从头开始匹配
s = re.match(r"\d+", "123, 我朋友的电话:456")
print(s)

# 预加载正则表达式 返回迭代器
obj = re.compile(r"\d+")
ret = obj.finditer("123, 我朋友的电话:456")
for it in ret:
    print(it.group())

ret = obj.findall("今天100000度")
print(ret)
# (?P<分组名>正则) 可以单独从正则匹配的内容中进一步提取内容
obj = re.compile(r"<div class='.*?'><span id='(?P<id>\d)+'>(?P<number>.*?)</span></div>", re.S)
 # re.S 让.能匹配换行符

result = obj.finditer(s)
for it in result:
    print(it.group("number"))
    print(it.group("id"))

()相当于隔开,c语言里的大括号。

?P<name>用这个为正则表达式命名,之后直接用名字调用

4. 豆瓣电影练习

import requests
import re
import csv

url ="https://movie.douban.com/top250"

dic = {
    "User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Mobile Safari/537.36 Edg/98.0.1108.56"
}

resp = requests.get(url, headers=dic)
page_content = resp.text

# 解析数据
obj = re.compile(r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)'
                 r'</span>.*?<p class="">.*?<br>(?P<year>.*?)&nbsp'
                 r'.*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>'
                 r'.*?<span>(?P<aud_num>.*?)人评价</span>', re.S)
# 开始匹配
result = obj.finditer(page_content)
f = open("data.csv", mode="w", encoding="utf-8")
csvwriter = csv.writer(f)
for it in result:
    # print(it.group("name"))
    # print(it.group("year").strip())
    # print(it.group("score"))
    # print(it.group("aud_num"))
    dic = it.groupdict()
    dic['year'] = dic['year'].strip()
    csvwriter.writerow(dic.values())
resp.close()

5. 电影天堂练习

1. 定位到2022必看片

2. 从2022必看片中提取子页面的链接地址

3. 请求子页面的链接地址,拿到所需的下载地址

import re
import requests

domain = "https://dytt89.com/"
resp = requests.get(domain, verify=False)
resp.encoding = 'gb2312' # 审查元素找到mata后,指定字符集
# print(resp.text)

# 那到ul里面的li
obj1 = re.compile(r"2022必看热片.*?<ul>(?P<ul>.*?)</ul>", re.S)
obj2 = re.compile(r"<a href='(?P<href>.*?)'")
obj3 = re.compile(r'◎片  名 (?P<movie>.*?)<br />.*? '
                  r'<td style="WORD-WRAP: break-word" '
                  r'bgcolor="#fdfddf"><a href="(?P<download>.*?)">', re.S)

result1 = obj1.finditer(resp.text)
child_href_list = []
for it in result1:
    ul = it.group('ul')

    # 提取子页面连接
    result2 = obj2.finditer(ul)
    for itt in result2:
        # 拼接子页面的url地址: 域名+子页面地址
        child_href = domain + itt.group('href').strip('/')
        child_href_list.append((child_href))

# 提取子页面内容
for href in child_href_list:
    child_resp = requests.get(href, verify=False)
    child_resp.encoding = 'gb2312'
    result3 = obj3.search(child_resp.text)
    print(result3.group("movie"))
    print(result3.group("download"))



resp.close()

6. bs4 北京新发地、热搜榜

1. 拿到页面源代码

2. 使用bs4进行解析,拿到数据

import requests
import re
from bs4 import BeautifulSoup
import csv

# 原网址有变化,用之前的方法可以提取
#
# url = "http://www.xinfadi.com.cn/getPriceData.html"
# resp = requests.get(url)
# obj = re.compile(r'.*?"prodName":"(?P<name>.*?)","prodCatid".*?')
#
# result = obj.finditer(resp.text)
# for it in result:
#     dic = it.groupdict()
#
#     print(dic['name'])

# 视频教程方法
# 使用微博热搜榜
url = "https://s.weibo.com/top/summary?Refer=top_hot&topnav=1&wvr=6"
dic = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 Edg/98.0.1108.56",
    "cookie": "f12 复制"
}
resp = requests.get(url, headers=dic)

f = open("resou.csv", mode="w", encoding="utf-8")
csvwriter = csv.writer(f)

# print(resp.text)
# 解析数据
# 1. 把页面交给BeautifulSoup进行处理,生成bs对象
page = BeautifulSoup(resp.text, "html.parser")  # 指定html解析器

# 2. 从bs对象中查找数据
# find(标签, 属性=值)
# find_all(标签, 属性=值)
tbody = page.find("tbody")  # 括号里可以加上 attr={"class":""}指定
# 拿到所有数据
trs = tbody.find_all("a")[1:]  # 一层层套
for tr in trs:  # tr为每一行数据
    name = tr.text
    csvwriter.writerow([name])

f.close()
resp.close()

7. 抓取图库图片

1. 拿到主页源代码,然后提取子页面连接,href

2. 通过href拿到子页面内容,找到 img->src

3. 下载图片

import requests
from bs4 import BeautifulSoup
import time

url = "https://www.umeitu.com/bizhitupian/weimeibizhi/"
resp = req
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值