HTTP请求
GET
最常见的一种请求方式,当客户端要从服务器中读取文档
POST
用于提交数据, 当采用 POST 方式向指定位置提交数据时,数据被包含在请求体中,服务器接收到这些数据后可能会建立新的资源、也可能会更新已有的资源。
HTTP 的 八大请求方式_http请求方式_roseLin...的博客-CSDN博客
HTTP请求的几种类型_http类型_菜瓜_牛顿的博客-CSDN博客
请求格式
请求行:
请求头:
Host+路径组成一个完整的网址
User-Agent用来告知服务器,客户端的信息
Accept是告诉服务器想接收什么数据
请求体:
告诉其他信息,一般在POST里面,GET里一般是空的
篡改请求头
由代码发出的请求的 User-Agent被标注为
有些网站只服务于真人,因此可以加上headers参数,伪装真实用户
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
}
result = re.get('https://www.bilibili.com/', headers=head)
*如何找到本机真实User-Agent?
浏览器内F12 - NetWork - 选择一项拉到底
响应格式
状态行
版本 状态码 状态消息
响应头
响应体
if 响应类型 is HTML:
爬取豆瓣Top250
先成功访问再说
import requests as re
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
}
result = re.get('https://movie.douban.com/top250', headers=head)
if result.ok:
print(result.text) # success
学亿点HTML基础
🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒🐒
网页解析库 Beautiful Soup
from bs4 import BeautifulSoup
BeautifulSoup将网页转化成树状结构
先练习爬一下片名
思路:只要中文片名,需要找到每个div class="hd"下的第一个<span class=“title”>
from bs4 import BeautifulSoup as bs
import requests as re
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
}
content = re.get('https://movie.douban.com/top250', headers=head).text
soup = bs(content, "html.parser")
hds = soup.findAll('div', attrs={'class': 'hd'})
for h in hds:
names = h.findAll('span', attrs={'class': 'title'})
print(names[0])
'''
<span class="title">肖申克的救赎</span>
<span class="title">霸王别姬</span>
<span class="title">阿甘正传</span>
<span class="title">泰坦尼克号</span>
。。。。。
'''
遍历所有页,取出250个
其实加个for循环就行了
from bs4 import BeautifulSoup as bs
import requests as re
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
}
index = 0 # 记录页数,一次加25
cnt = 1 # 记录No.12345
while index != 250:
content = re.get('https://movie.douban.com/top250?start='+str(index), headers=head).text
soup = bs(content, "html.parser")
hds = soup.findAll('div', attrs={'class': 'hd'})
for h in hds:
names = h.findAll('span', attrs={'class': 'title'})
print('No.'+str(cnt), end=' ')
print(names[0].string) # 每一个hd里面的第一个span
cnt += 1
index += 25
'''
No.1 肖申克的救赎
No.2 霸王别姬
No.3 阿甘正传
No.4 泰坦尼克号
No.5 这个杀手不太冷
No.6 千与千寻
。。。。。
'''
指定搜索内容
可直接通过修改url
干百度翻译
获取请求形式
三个sug包分别是d, do, dog,可以看出请求URL
响应头是个json
import requests as re
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
}
data = {'kw': 'rose'}
result = re.post('https://fanyi.baidu.com/langdetect', data=data, headers=head)
# json返回的是对象,确认响应是对象才能用
print(result.json())
爬KFC餐厅名称
URL:肯德基餐厅信息查询
请求完局部刷新,阿贾克斯请求,就抓包XHR
import requests as re
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
}
para = {'cname': '',
'pid': '',
'keyword': '上海',
'pageIndex': '1',
'pageSize': '10'}
result = re.post('https://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword', params=para, headers=head)
# json返回的是对象,确认响应是对象才能用
print(result.text)
XPath
python爬虫之xpath解析(附实战)_python爬取数据返回空列表_猛男技术控的博客-CSDN博客
xpath解析原理:
- 1 .实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中。
- 2.调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获。
浏览器内可以直接获取xpath路径
爬58二手房
from lxml import etree
import requests as re
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
}
url = 'https://sh.58.com/ershoufang/'
result = re.get(url=url, headers=head).text
# print(result)
tree = etree.HTML(result)
div_list = tree.xpath('/html/body/div[1]/div/div/section/section[3]/section[1]/section[2]/div')
# print(div_list)
for house in div_list:
# [' 假一罚万 万科有山 豪装下叠 拎包入住 南北双花园']加个[0]只取内容文字
# ./ 从当前标签路径开始往下解析
name = house.xpath('./a/div[2]/div[1]/div[1]/h3//text()')[0]
print(name)
爬壁纸天堂
URL:Top Wallpapers - wallhaven.cc
先成功请求网址
from time import sleep
from lxml import etree
import requests as re
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
}
url = 'https://wallhaven.cc/toplist'
# 得到网站html内容
result = re.get(url=url, headers=head).text
# print(result)
解析到图片列表
注意得到列表时,不能只得到列表总体对象,要访问到具体列表内容项目
# xpath解析网址图片列表
tree = etree.HTML(result)
# li即为一个个图片项,ul为整个图片列表,需要解析至li
img_list = tree.xpath('/html/body/main/div[1]/section[1]/ul/li')
print('已获取到源列表。。。')
# print(img_list)
开始循环访问列表
cnt = 1
for li in img_list[:3]:
print('正在获取li[' + str(cnt) + ']...')
big_img_url = li.xpath('./figure/a/@href')[0] # 外面是缩略图,得到大图的网址url
print('大图网址:' + big_img_url, end=' ') # https://wallhaven.cc/w/rrowwm
# 请求大图实际网址,并解析到图片源文件
big_img_url_result = re.get(url=big_img_url, headers=head).text
tree1 = etree.HTML(big_img_url_result)
img_xp = tree1.xpath('/html/body/main/section/div[1]/img/@src')[0]
print('大图资源:' + img_xp) # https://w.wallhaven.cc/full/gp/wallhaven-gp9god.jpg
# 请求图片源文件二进制数据,切分得到图片名字
big_img = re.get(url=img_xp, headers=head).content
name = str(img_xp).rsplit('/', 1)[-1].rsplit('-')[-1] # /wallhaven-rrowwm.png -> rrowwm.png
with open(fr'./{name}', 'wb') as f:
f.write(big_img)
print('save ' + name + '!')
sleep(0.5) # 访问慢一点
cnt += 1 # 计数器++
成品打包
https://download.csdn.net/download/qq_58551342/87976931
解决验证码
本质就是根据图片ORC识别
超级鹰验证码识别-专业的验证码云端识别服务,让验证码识别更快速、更准确、更强大
Cookie
why
当登录请求发出后,在去爬取个人主页等信息,第二次的请求是不会记录之前登录的信息的,请求到的还是没有身份信息的网页,so,需要cookie
自动获取cookie—session
cookie有生命周期,所以不能写死
session用于请求的发送,如果过程中产生了cookie,可以存在session对象中
获取登录请求页时使用session对象即可
session = re.session()
result1 = session.post(url=login_url, headers=head)
result2 = session.get(url=user_url, headers=head)
代理(破解封ip)
反爬:封ip
反反爬:代理
代理、正向代理与反向代理_lgily-1225的博客-CSDN博客
result = re.get(url=url, headers=head, proxies={'https': 'ip:port'})
exchange(DN, CS)你甜美有bug知道吗?
线程池
多县城、多进程
进程和线程关系及区别_线程和进程的关系和区别_yaosiming2011的博客-CSDN博客
- 可以单独为阻塞操作开启线程或进程
- 无法无限制开999999999个
线程池、进程池
- 可以降低系统对进程或者线程创建和销毁的一个频率,从而很好的降低系统的开销。
- 池中线程进程有上限
Pool模板代码
import time
from multiprocessing.dummy import Pool
from time import sleep
def op(url):
print('start '+ url)
sleep(2)
print('end')
url_list = ['111',
'222',
'333',
'444']
start = time.time()
# 实例化一个线程池
pool = Pool(3)
pool.map(op, url_list)
end = time.time()
print(str(end-start)+'s')
pool.close() # 关闭线程池
pool.join() # 等子线程结束再结束主线程
'''
start 111
start 222
start 333
end
end
start 444
end
end
4.028931379318237s
'''
单线程+异步协程
什么牛马协程,不用了!
协程(概念节)
早期greenlet协程
asyncio
python3.4+
- async and await
python3.5+
意义
遇到IO等待时间,再去干点别的事(下载就是网络IO的一种形式)
异步编程
事件循环
# 生成一个事件循环
loop = asyncio.get_event_loop()
# 任务放到循环里
loop.run_until_complete(task)
协程函数
定义一个协程函数,执行协程函数得到一个携程对象
async def func():
pass
result = fun()
执行创建协程对象,协程函数内的语句不会执行
想要运行,要将协程对象交给事件循环
import asyncio
async def func():
print('jntm')
result = func()
# # 生成一个事件循环
# loop = asyncio.get_event_loop()
# # 任务放到循环里
# loop.run_until_complete(result)
asyncio.run(result) # python 3.7新功能,一行搞定
await
await+可等待的对象(携程对象,Task对象)> IO等待
async def other():
print('other()') # 2
await asyncio.sleep(2) # 3
print('other end') # 4
async def fun():
print('fun') # 1
resp = await other()
print('end: ', resp) # 5
loop = asyncio.get_event_loop()
loop.run_until_complete(fun())
使劲理解await和loop相互作用,task好几个时,函数里有await,切到其它函数
import asyncio
import time
import requests
async def test2(i):
print('test', i)
await asyncio.sleep(2)
r = requests.get(i)
print(i, r)
url = ["https://segmentfault.com/p/1210000013564725",
"https://www.jianshu.com/p/83badc8028bd",
"https://www.baidu.com/"]
loop = asyncio.get_event_loop()
task = [asyncio.ensure_future(test2(i)) for i in url]
start = time.time()
loop.run_until_complete(asyncio.wait(task))
endtime = time.time() - start
print(endtime)
loop.close()
'''
test https://segmentfault.com/p/1210000013564725
test https://www.jianshu.com/p/83badc8028bd
test https://www.baidu.com/
https://segmentfault.com/p/1210000013564725 <Response [200]>
https://www.jianshu.com/p/83badc8028bd <Response [403]>
https://www.baidu.com/ <Response [200]>
2.6141810417175293
'''
Future
这个不会用
selenium
- 便捷获取动态加载数据
- 模拟登录
下载对应浏览器驱动
selenium之 chromedriver与chrome版本映射表(更新至v2.46)_selenium版本对应chrome_huilan_same的博客-CSDN博客
实例化一个浏览器对象
from selenium import webdriver
bro = webdriver.Chrome(executable_path='D:\Google\chromedriver_win32\chromedriver.exe')
获取页面
bro.get('url')
page = bro.page_source
一些操作
from time import sleep
from selenium import webdriver
bro = webdriver.Chrome(executable_path='D:\Google\chromedriver_win32\chromedriver.exe')
bro.get('https://www.taobao.com/')
input = bro.find_element_by_xpath('//*[@id="q"]')
input.send_keys('蔡徐坤')
sleep(2)
# 滚动操作
bro.execute_script('window.scrollTo(0, document.body.scrollHeight/2)')
sleep(2)
# click
yes_button = bro.find_element_by_xpath('//*[@id="J_TSearchForm"]/div[1]/button')
yes_button.click()
sleep(2)
# get again
bro.get('https://www.baidu.com')
sleep(2)
# back
bro.back()
sleep(2)
# 前进
bro.forward()
bro.close()
iframe处理
示例网站:菜鸟教程在线编辑器
直接定位iframe中的内容,会显示如下错误(没有这样一个标签)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//*[@id="draggable"]"}
(Session info: chrome=114.0.5735.134)
要先切换脚本的作用域,再在iframe新域中定位标签
bro.switch_to.frame('iframeResult') # 标签id
div = bro.find_element_by_xpath('/html/body/div[2]')
动作链
action = ActionChains(bro)
# 点击且长安
action.click_and_hold(div)
for i in range(5):
# x,y方向拖动像素,perform立即执行
action.move_by_offset(20,0).perform()
sleep(1)
action.release()
QQ空间登录
from time import sleep
from allpath import dirver_path
from selenium import webdriver
from lxml import etree
bro = webdriver.Chrome(executable_path=dirver_path)
bro.get('https://qzone.qq.com/')
# 切换到iframe
bro.switch_to.frame('login_frame')
# 点击密码登录
ex_div = bro.find_element_by_xpath('//*[@id="switcher_plogin"]')
ex_div.click()
# 获取账号密码域并输入
zhanghao = bro.find_element_by_xpath('//*[@id="u"]')
zhanghao.send_keys('xxxxxxxxxx')
sleep(0.5)
mima = bro.find_element_by_xpath('//*[@id="p"]')
mima.send_keys('xxxxxxxxxxxx')
sleep(0.5)
# 点击登录
denglu = bro.find_element_by_xpath('/html/body/div[1]/div[5]/div/div[1]/div[3]/form/div[4]/a/input')
denglu.click()
成功登录!
无头浏览器(就是看不见浏览器)
from selenium.webdriver.chrome.options import Options
op = Options()
op.add_argument(argument='--headless')
op.add_argument('--disable-gpu')
bro = webdriver.Chrome(executable_path=dirver_path, chrome_options=op)
假装自己不是selenium
# 伪装自己不是selenium
from selenium.webdriver import ChromeOptions
op2 = ChromeOptions()
op2.add_experimental_option('excludeSwitches', ['enable-automation'])
Scrapy框架
pip install scrapy -i https://pypi.tuna.tsinghua.edu.cn/simple
准备工作
终端内操作
建项目
scrapy startproject firstScrapy(自己取个项目名)
创建爬虫源文件
>> scrapy genspider 文件名 www.baidu.com(随便跟个url,之后能改)
文件创建在了spiders文件夹下
修改文件
import scrapy
class MyfileSpider(scrapy.Spider):
name = 'myfile'
# 限定下面哪个基本域名可以请求,不用得了
# allowed_domains = ['www.baidu.com']
start_urls = ['https://www.baidu.com/']
# 解析数据
def parse(self, response):
print(response)
修改一个小配置
setting.py中
执行文件
>scrapy crawl myfile [--nolog(不要日志信息)]
*修改日志等级
setting中加入 LOG_LEVEL = 'ERROR'