
python爬虫学习笔记(基于尚硅谷)
本人入门python爬虫的学习笔记,记录了我学习过程中遇到的问题和解决方法,希望能帮助到想要吃下这个技术的同学
01.urllib
通过一个程序,根据Url进行爬取网页,获取有用信息 使用程序模拟浏览器,去向服务器发送请求,获取响应信息
反爬手段
1.User‐Agent 2.代理IP 3.验证码访问 4.数据加密
5.动态加载网页 网站返回的是js数据 并不是网页的真实数据
urllib一个类型六个方法
import urllib.request
url = 'http://baidu.com'
response = urllib.request.urlopen(url)
#response是HTTPResponse的类型
'print(type(response))'
#按字节读
content1 = response.read(5)
#按行读
content2 = response.readline()
print(content2)
content3 = response.readlines()
print(content3)
#状态码
print(response.getcode())
#地址
print(response.geturl())
#获取状态信息
print(response.getheaders())
urllib下载
import urllib.request
#页面
url_page = 'http://www.baidu.com'
urllib.request.urlretrieve(url_page,'baidu.html')
#图片
url_img = 'https://tse3-mm.cn.bing.net/th/id/OIP-C.mNqPTNrIJLPdTDtgeTE7MAHaLH?w=186&h=279&c=7&r=0&o=5&dpr=1.5&pid=1.7'
urllib.request.urlretrieve(url_img,filename='lisa.jpg')
#视频
url_video = '视频url'
urllib.request.urlretrieve(url_video,'cat.mp4')
请求对象定制
import urllib.request
url = 'https://cn.bing.com/search?q=%E5%91%A8%E6%9D%B0%E4%BC%A6&form=ANNTH1&refig=9e63813a16cf4a9fb53ed3f604bcb4f4'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
}
#请求对象定制 urlopen不能存字典
#请求对象的定制 ua反爬
request = urllib.request.Request(url=url,headers = headers)
response = urllib.request.urlopen(request)
content = response.read().decode('UTF-8')
print(content)
get请求方式:urllib.parse.quote()
import urllib.request
import urllib.parse
#获取网页源码
url = 'https://www.baidu.com/s?wd='
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
}
#将周杰伦变成unicod
name = urllib.parse.quote('周杰伦')
#根据值获取
url = url + name
request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
get请求方式:urllib.parse.urlencode()
import urllib.request
import urllib.parse
base_url = 'https://www.baidu.com/s?'
data = {
'wd':'周杰伦',
'sex':'男',
'location':'中国台湾'
}
new_data = urllib.parse.urlencode(data)
url = base_url + new_data
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
}
request = urllib.request.Request(url = url,headers = headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
post请求方式
import urllib.request
url = 'https://fanyi.baidu.com/sug'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
}
data = {
'kw':'spider'
}
#post请求的参数 必须要进行编码
data = urllib.parse.urlencode(data).encode('utf-8')
request = urllib.request.Request(url=url,data=data,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
import json
obj = json.loads(content)
print(obj)
总结:post和get区别?
1:get请求方式的参数必须编码,参数是拼接到url后面,编码之后不需要调用encode方法
2:post请求方式的参数必须编码,参数是放在请求对象定制的方法中,编码之后需要调用encode方法
ajax豆瓣电影前十页 get请求
ajax是一种用于创建快速动态网页的技术。
通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。
这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
#下载豆瓣电影前10页数据
#1、请求对象定制
#2、获取响应数据
#3、下载数据
import urllib.parse
import urllib.request
def creat_request(page):
base_url = 'https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&'
data = {
'start':(page-1)*20,
'limit':20
}
data = urllib.parse.urlencode(data)
url = base_url + data
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
}
request = urllib.request.Request(url=url,headers=headers)
return request
def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content
def down_load(page,content):
with open('douban'+ str(page) +'.json','w',encoding='utf-8')as fp:
fp.write(content)
#入口(可选)
if __name__ == '__main__':
start_page = int(input('请输入起始页码'))
end_page = int(input('请输入结束页码'))
for page in range(start_page,end_page+1):
#每一页都有自己请求对象的定制
request = creat_request(page)
content = get_content(request)
#下载
down_load(page,content)
ajax 请求kfc网站 post请求
import urllib.request
import urllib.parse
def create_request(page):
base_url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname'
data = {
'cname': '宜昌',
'pid':'',
'pageIndex': page,
'pageSize': '10'
}
data = urllib.parse.urlencode(data).encode('utf-8')
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
'Cookie':'route - cell = ksa;ASP.NET_SessionId = 5lvicybh0c1hvcltu04vpz3m;Hm_lvt_1039f1218e57655b6677f30913227148 = 1682253815;Hm_lpvt_1039f1218e57655b6677f30913227148 = 1682253815;SERVERID = 6ee43946432b1a5105f8c6178eb14f6d | 1682260334 | 1682260068'
}
request = urllib.request.Request(url=base_url,headers=headers,data=data)
def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content
def down_load(page,content):
with open('kfc_'+str(page)+'.json','w',encoding='utf-8')as fp:
fp.write(content)
if __name__ == '__main__':
start_page = int(input('请输入起始页码:'))
end_page = int(input('请输入结束页码'))
for page in range(start_page,end_page+1):
request = create_request(page)
content = get_content(request)
down_load(page,content)
异常处理
import urllib.request
import urllib.error
#url = 'https://blog.csdn.net/weixin_46211269/article/details/126121311'
url = 'http://www.goudan1111.com'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
'Cookie': 'route - cell = ksa;ASP.NET_SessionId = 5lvicybh0c1hvcltu04vpz3m;Hm_lvt_1039f1218e57655b6677f30913227148 = 1682253815;Hm_lpvt_1039f1218e57655b6677f30913227148 = 1682253815;SERVERID = 6ee43946432b1a5105f8c6178eb14f6d | 1682260334 | 1682260068'
}
try:
request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
except urllib.error.HTTPError:
print('系统正在升级')
except urllib.error.URLError:
print('系统正在升级')
cookie登录
#数据采集时,需要绕过登录,然后进入到某个页面
#个人信息页面是utf-8 但还是报编码错误 因为没有进入到个人页面 而是跳转
#到登录页面 登录页面不是utf-8
import urllib.request
url = 'https://weibo.com/u/5398458536'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}
request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('gb2312')
print(content)
#数据保存
with open('weibo.html','w',encoding='gb2312')as fp:
fp.write(content)
Handler处理器
定制更高级的请求头(随着业务逻辑的复杂 请求对象的定制已经满足不了我们的需求(动态cookie和代理 不能使用请求对象的定制)
import urllib.request
url = 'http://www.baidu.com'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}
request = urllib.request.Request(url=url,headers=headers)
#handler bulid_open open
#获取handler对象
handler = urllib.request.HTTPHandler()
#获取opener对象
opener = urllib.request.build_opener(handler)
#调用open方法
response = opener.open(request)
content = response.read().decode('utf-8')
print(content)
代理的基本使用
代码配置代理
- 创建Reuqest对象
- 创建ProxyHandler对象
- 用handler对象创建opener对象
- 使用opener.open函数发送请求
import urllib.request
url = 'http://www.baidu.com/s?wd=ip'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}
request = urllib.request.Request(url=url,headers=headers)
proxies={
'http':'58.20.184.187:9091'
}
handler = urllib.request.ProxyHandler(proxies=proxies)
opener = urllib.request.build_opener(handler)
response = opener.open(request)
content = response.read().decode('utf-8')
with open('daili.html','w',encoding='utf-8')as fp:
fp.write(content)
代理池
import urllib.request
proxies_pool = [
{ 'http':'118.24.219.151:16817' },
{ 'http':'118.24.219.151:16111'}
]
#从代理池中随机选择一个
import random
proxies = random.choice(proxies_pool)
#后面用handler包装
02.解析
xpath 使用 Ctrl + Shlft + x
#xpath解析
#1.本地文件 etree.parse
#2.服务器响应的数据 response.read().decode('utf-8) etree.HTML()
xpath基本语法:
1.路径查询
查找所有子孙节点,不考虑层级关系
找直接子节点
2.谓词查询
div[@id]
div[@id=“maincontent”]
3.属性查询
@class
4.模糊查询
div[contains(@id, “he”)]
div[starts‐with(@id, “he”)]
5.内容查询
div/h1/text()
6.逻辑运算
div[@id=“head” and @class=“s_down”]
title | price
#解析本地文件
tree = etree.parse('070解析xpath基本使用.html')
#tree.xpath('xpath路径')
#查找ul下的li
li_list = tree.xpath('//body/ul/li')
#查找所有有id的属性的li标签
#text()获取标签中的内容
li_list = tree.xpath('//ul/li[@id]/text()')
#找到id为11的li标签 注意引号
li_list = tree.xpath('//ul/li[@id="11"]/text()')
#查找到id为11的li标签的class的属性值
li_list = tree.xpath('//ul/li[@id="11"]/@class')
#查找id中包含1的li标签
li_list = tree.xpath('//ul/li[contains(@id,"1")]/text()')
#查询id的值以1开头的li标签
li_list = tree.xpath('//ul/li[starts-with(@id,"c")]/text()')
#查询id为11和class为c1的
li_list = tree.xpath('//ul/li[@id="11" and @class="c1"]/text()')
#
li_list = tree.xpath('//ul/li[@id="11"]/text() | //ul/li[@id="12"]/text()')
#判断列表长度
print(li_list)
print(len(li_list))
综合使用xpath解析
#获取网站源码
#解析 解析服务器响应的文件 etree.HTML
#打印
import urllib.request
url = 'https://www.baidu.com/'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}
requests = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(requests)
content = response.read().decode('utf-8')
#解析网页源码 获取要的数据
from lxml import etree
#解析服务器响应文件
tree = etree.HTML(content)
#获取想要的数据 xpath的返回值是列表类型的数据
#浏览器可直接复制获取xml
result = tree.xpath('//input[@id="su"]/@value')[0]
print(result)
站长素材网站图片爬取
#需求 下载前10页图片
#https://sc.chinaz.com/tupian/qinglvtupian.html
#https://sc.chinaz.com/tupian/qinglvtupian_2.html
import urllib.request
from lxml import etree
def creat_request(page):
if(page == 1):
url = 'https://sc.chinaz.com/tupian/qinglvtupian.html'
else:
url = 'https://sc.chinaz.com/tupian/qinglvtupian_'+str(page)+'.html'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36'
}
request =urllib.request.Request(headers=headers,url=url)
return request
def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content
def down_load(content):
# 下载图片
tree = etree.HTML(content)
name_list = tree.xpath('//div[@class="container"]//img/@alt')
#一般涉及图片的网站都会进行懒加载
img_list = tree.xpath('//div[@class="container"]//img/@data-original')
for i in range(len(name_list)):
name = name_list[i]
img = img_list[i]
url = 'https:' + img
# urllib.request.urlretrieve('图片地址','文件名字')
urllib.request.urlretrieve(url=url,filename='./loveImg/'+name+'.jpg')
# .loveImg为目录名 放在...目录下
if __name__ == '__main__':
start_page = int(input("请输入起始页码"))
end_page = int(input("请输入结束页码"))
for page in range(start_page,end_page+1):
#请求对象定制
request = creat_request(page)
# 获取网页源码
content = get_content(request)
# 下载
down_load(content)
JSONpath基本语法
缺点:无法解析服务器响应的数据
案例:
{ "store": {
"book": [
{ "category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{ "category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{ "category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{ "category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}
语法:
obj = json.load(open('073解析jsonpath.json','r',encoding='utf-8'))
#书店所有书的作者
author_list = jsonpath.jsonpath(obj,'$.store.book[*].author')
#所有的作者
author_list = jsonpath.jsonpath(obj,'$..author')
#store下的所有元素
tag_list = jsonpath.jsonpath(obj,'$.store.*')
#store下所有的price
price_list = jsonpath.jsonpath(obj,'$.store..price')
#第三个书
book = jsonpath.jsonpath(obj,'$..book[2]')
#最后一本书
book = jsonpath.jsonpath(obj,'$..book[(@.length-1)]')
#前两本书
book_list = jsonpath.jsonpath(obj,'$..book[0,1]')
book_list = jsonpath.jsonpath(obj,'$..book[:2]')
#过滤出所有包含isbn的书 条件过滤需要在()前加一个?
book_list = jsonpath.jsonpath(obj,'$..book[?(@.isbn)]')
#那本书超过10块钱
book_list = jsonpath.jsonpath(obj,'$..book[?(@.price>10)')
JSONpath解析淘票票网站城市
import urllib.request
url = 'https://dianying.taobao.com/cityAction.json?activityId&_ksTS=1687975134652_108&jsoncallback=jsonp109&action=cityAction&n_s=new&event_submit_doGetAllRegion=true'
headers = {
'Cookie':'t=a7d009fb8c7d40083be5844676f3955e; cookie2=14f2996b749e6492ee3a6c304cdf58f0; v=0; _tb_token_=f8514e7636eee; cna=Aa7CHMZlFjsCAXWWBoxRWAzg; xlly_s=1; tb_city=110100; tb_cityName="sbG+qQ=="; tfstk=dugJF7fyJKvkEwApr8KD88y1fndDm4hyZYl1-J2lAxHxQYdzxgmov9ex1QykY3kKDvM4q8gKTwFIOvRzKQ-mabzURdvgJFcraZVVGyF6nFGRS0JMIFYMVsaped0hBJmGjNfNSdT5oA3QNHwZ0_nAGKPz2RGvbw_pv76gBb1dJwgxquBaoV099e6gBWjWMIIFYuNq8_x0_; l=fBE4_1-lN4I9l8kXBO5BFurza77TzIRb81PzaNbMiIEGa6tP9FwyqNC1pheDWdtjgT5xsetrip0J_dFyl-UU-dsWHpfuKtyuJev68eM3N7AN.; isg=BLS04fS1bHu-f_i3iogL2Ff9hXImjdh3ZG1PEk4VnD_CuVUDdpuRBtx3OfFhRhDP',
'Referer':'https://dianying.taobao.com/?spm=a1z21.3046609.city.1.32c0112aTVArVg&city=110100'
}
request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
#切割 json不能有多余的括号
content = content.split('(')[1].split(')')[0]
with open('074解析jsonpath淘票票.json','w',encoding='utf-8')as fp:
fp.write(content)
import json
import jsonpath
obj = json.load(open('074解析jsonpath淘票票.json','r',encoding='utf-8'))
city_list = jsonpath.jsonpath(obj,'$..regionName')
print(city_list)
BeautifulSoup(bs4)
主要功能也是解析和提取数据
缺点:效率没有lxml的效率高
优点:接口设计人性化,使用方便
BeautifulSoup基本用法
from bs4 import BeautifulSoup
#解析本地文件 来将bs4的基础语法进行讲解
#默认gbk打开时需要指定编码
soup = BeautifulSoup(open('075解析bs4的基本使用.html',encoding='utf-8'),'lxml')
#根据标签名查找节点
#找到的是第一个符合条件的数据
print(soup.a)
#获取标签的属性和属性值
print(soup.a.attrs)
#bs4的一些函数
#(1)find
#返回第一个符合条件的数据
print(soup.find('a'))
#根据title值来找到对应的标签对象
print(soup.find('a',title="a2"))
#根据class的值来找到对应的标签对象 注意class需要添加下划线
print(soup.find('a',class_="a2"))
#(2)find_all 返回的是一个列表 并且返回了所有a的标签
print(soup.find_all('a'))
#如果想获取多个标签的数据 那么需要find_all的参数中添加列表的数据
print(soup.find_all(['a','span']))
#limit查找前几个数据
print(soup.find_all('li',limit=2))
#(3)select(推荐) 返回一个列表 并且返回多个数据
print(soup.select('a'))
#可以通过.代表class 类选择器 #代表id
print(soup.select('.a2'))
print(soup.select('#li'))
#属性选择器--通过属性寻找对应标签
#查找到li标签中有id的标签
print(soup.select('li[id]'))
#查找到li标签中id为l2的标签
print(soup.select('li[id="l2"]'))
#层级选择器
# 后代选择器
#找到div下的li
print(soup.select('div li'))
#子代选择器
# 某标签的第一级子标签
print(soup.select('div > ul > li'))
#找到a标签和li标签的所有对象
print(soup.select('a,li'))
#节点信息
# 获取节点内容
obj = soup.select('#d1')[0]
#如果标签对象中 只有内容 那么string和get_text()都可以使用
#如果标签对象中 除了内容还有标签 那么string获取不到数据
print(obj.string)
print(obj.get_text())
#节点的属性
obj = soup.select('#p1')[0]
#name是标签的名字
print(obj.name)
#将属性值左右一个字典返回
print(obj.attrs)
#获取节点属性
obj = soup.select('#p1')[0]
print(obj.attrs.get('class'))
print(obj.get('class'))
print(obj['class'])
Bs4爬取星巴克
import urllib.request
url = 'https://www.starbucks.com.cn/menu/'
response = urllib.request.urlopen(url)
content = response.read().decode('utf-8')
from bs4 import BeautifulSoup
soup = BeautifulSoup(content,'lxml')
#xpath路径://ul[@class="grid padded-3 product"]//strong
name_list = soup.select('ul[class="grid padded-3 product"] strong')
for name in name_list:
print(name.get_text())
03.selenium无图形化浏览器
模拟浏览器功能,自动执行网页中的js代码,实现动态加载
基本使用
from selenium import webdriver
#创建浏览器操作对象
path = 'chromedriver.exe'
browser = webdriver.Chrome(path)
#访问网站
url = 'https://www.JD.com'
browser.get(url)
#获取网页源码
content = browser.page_source
print(content)
元素定位
#根据id找到对象 常用
button = browser.find_element_by_id('su')
#根据标签属性的属性值来获取对象
button = browser.find_element_by_name('wd')
#根据xpath语句来获取对象 常用
button = browser.find_element_by_xpath('//input[@id="su"]')
#根据标签的名字获取对象
button = browser.find_element_by_tag_name('input')
#使用css语法获取对象 常用
button = browser.find_element_by_css_selector('#su')
#根据链接文本获取
button = browser.find_element_by_link_text('新闻')
元素信息
input = browser.find_element_by_id('su')
#获取标签属性
print(input.get_attribute('class'))
#获取标签名字
print((input.tag_name))
#获取元素文本
a=browser.find_element_by_link_text('新闻')
print(a.text)
自动化交互
#获取文本框对象
input = browser.find_element_by_id('kw')
#文本框输入周杰伦
input.send_keys('周杰伦')
time.sleep(2)
#获取百度一下按钮
button = browser.find_element_by_id('su')
#点击按钮
button.click()
time.sleep(2)
#滑倒底部
js_bottom = 'document.documentElement.scrollTop=100000'
browser.execute_script(js_bottom)
time.sleep(2)
#获取下一页按钮
next = browser.find_element_by_xpath('//a[@class="n"]')
next.click()
time.sleep(2)
#回到上一页
browser.back()
time.sleep(2)
#回到下一页
browser.forward()
time.sleep(3)
#退出
browser.quit()
Phantomjs无界面浏览器
from selenium import webdriver
path = 'phantomjs.exe'
browser = webdriver.PhantomJS(path)
url = 'https://www.baidu.com'
browser.get(url)
chrome handless无界面浏览器
封装
#封装的handless
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def share_browser():
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable‐gpu')
# path是你自己chrome浏览器的文件路径
path = r'C:\Program Files\Google\Chrome\Application\chrome.exe'
chrome_options.binary_location = path
browser = webdriver.Chrome(chrome_options=chrome_options)
return browser
封装调用
browser = share_browser()
url = 'https://www.baidu.com'
browser.get(url)
04.requests
文档:
官方文档 Requests: 让 HTTP 服务人类 — Requests 2.18.1 文档
快速上手 快速上手 — Requests 2.18.1 文档
基本使用
import requests
url = 'http://www.baidu.com'
response = requests.get(url=url)
#一个类型和六个属性
#Response类型
print(type(response))
#设置响应的编码格式
response.encoding = 'utf-8'
#以字符串的形式返回网页源码
print(response.text)
#返回一个url地址
print(response.url)
#返回二进制数据
print(response.content)
#返回响应状态码
print(response.status_code)
#返回响应头
print(response.headers)
requests的get请求
参数使用params传递
参数无需urlencode编码
不需要请求对象的定制
请求资源路劲中?可以不加
import requests
url = 'http://www.baidu.com/s'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
'Cookie': 'BIDUPSID=D043207FA0BA8EDA6DE237D13B7A2085; PSTM=1679819122; BAIDUID=D043207FA0BA8EDA6B95F9AF636CC568:FG=1; BAIDUID_BFESS=D043207FA0BA8EDA6B95F9AF636CC568:FG=1; ZFY=SRkQXXk5q963dsWp6MbBx:A9BVsfItJEu2v0jm:BIARX0:C; APPGUIDE_10_0_2=1; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; H_PS_PSSID=38515_36561_38470_38468_38375_37936_38387_38356_26350; BA_HECTOR=200k85012hag2kag808h24dm1i3nmlg1n; PSINO=6; delPer=0; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BCLID=8184894944099422743; BCLID_BFESS=8184894944099422743; BDSFRCVID=EKtOJexroG07VWbfMcMcMWLvdFweG7bTDYrEOwXPsp3LGJLVFe3JEG0Pts1-dEu-S2OOogKKLgOTHUCF_2uxOjjg8UtVJeC6EG0Ptf8g0M5; BDSFRCVID_BFESS=EKtOJexroG07VWbfMcMcMWLvdFweG7bTDYrEOwXPsp3LGJLVFe3JEG0Pts1-dEu-S2OOogKKLgOTHUCF_2uxOjjg8UtVJeC6EG0Ptf8g0M5; H_BDCLCKID_SF=tRAOoC_-tDvDqTrP-trf5DCShUFs0xnJB2Q-XPoO3KtbSx3PbxcjXttI3PvqKU5f5mkf3fbgy4op8P3y0bb2DUA1y4vp0tLeWeTxoUJ2-KDVeh5Gqq-KXU4ebPRiWPb9QgbP5hQ7tt5W8ncFbT7l5hKpbt-q0x-jLTnhVn0MBCK0HPonHj8WDj5b3O; H_BDCLCKID_SF_BFESS=tRAOoC_-tDvDqTrP-trf5DCShUFs0xnJB2Q-XPoO3KtbSx3PbxcjXttI3PvqKU5f5mkf3fbgy4op8P3y0bb2DUA1y4vp0tLeWeTxoUJ2-KDVeh5Gqq-KXU4ebPRiWPb9QgbP5hQ7tt5W8ncFbT7l5hKpbt-q0x-jLTnhVn0MBCK0HPonHj8WDj5b3O; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1680340062,1681644218; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1681644271; ab_sr=1.0.1_ODQ3MWVjOTRjMmNhZjlmMzdlZGExZDUzNjZjNzBjZjVkOTIwOTE0MTVmNzg2NDVmMWM5YTc1MTQxMWMxYTMyODgzNDhjODQyMzZlNjZiYmE1Mjg2YTBhZGE4NGNhNTVlN2Y4Y2ExNzNkYjBkZjM3MGYxMTIwMDk0NDFkNzBiMzdkZjJiODFkZTlmNWJmMWE4ODQ5ZjE5ZDRjMmJlODRhNQ=='
}
data = {
'wd':'北京'
}
#url请求资源路径 params参数 kwargs字典
response = requests.get(url=url,params=data,headers=headers)
response.encoding = 'utf-8'
content = response.text
print(content)
requests的post请求
post请求不需要编解码
post请求参数是data
不需要请求对象的定制
import requests
url = 'https://fanyi.baidu.com/sug'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
}
data = {
'kw':'eye'
}
response = requests.post(url=url,data=data,headers=headers)
content = response.text
import json
obj = json.loads(content)
print(obj)
requests代理
import requests
url = 'http://www.baidu.com/s?'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
}
data = {
'wd':'ip'
}
#代理的ip
proxy = {
'http':'60.167.20.156:1133'
}
response = requests.get(url=url,headers=headers,params=data,proxies=proxy)
response.encoding = 'utf-8'
content = response.text
with open('daili.html','w',encoding='utf-8')as fp:
fp.write(content)
requests的cookie登录 古诗文网
#通过登录 进入到主页面
#通过登陆接口发现 登录的时候需要的参数很多
# __VIEWSTATE: CP3QIJUj3fNNIMyAbBfpI+sp27YaeFH9BAe8qKi8JPdvSus4hqUknovahzQOhH5mAC+Z2cQZ8XESxKjvBC19ufH9dBIjEV1ezk3LHvHkiAMKF3NLdZmW86c4D7DDjqiiY4y3/lkVY86V7w09qbcEI97FfcE=
# __VIEWSTATEGENERATOR: C93BE1AE
# from: http://so.gushiwen.cn/user/collect.aspx
# email: 17609092650
# pwd: 122456
# code: ey2l
# denglu: 登录
#观察到__VIEWSTATE、__VIEWSTATEGENERATOR、code是变量
#难点(1)隐藏域__VIEWSTATE __VIEWSTATEGENERATOR 一般情况下看不到的数据都在页面源码中
# 观察到两个数据在页面源码 所以需要获取页面源码 然后进行解析就可以获取了
# (2)验证码
import requests
#登录页面的url地址
url = 'https://so.gushiwen.cn/user/login.aspx?from=http://so.gushiwen.cn/user/collect.aspx'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'
}
#获取页面源码
response = requests.get(url=url,headers=headers)
content = response.text
#解析页面源码 然后获取__VIEWSTATE、__VIEWSTATEGENERATOR
from bs4 import BeautifulSoup
soup = BeautifulSoup(content,'lxml')
#获取__VIEWSTATE
viewstate = soup.select('#__VIEWSTATE')[0].attrs.get('value')
#获取__VIEWSTATEGENERATOR
viewstategenerator = soup.select('#__VIEWSTATEGENERATOR')[0].attrs.get('value')
#获取验证码图片
code = soup.select('#imgCode')[0].attrs.get('src')
code_url = 'https://so.gushiwen.cn' + code
#requests里有一个方法session()通过session的返回值 就能使用请求变成一个对象
session = requests.session()
#验证码的url的内容
response_code = session.get(code_url)
#注意此时要用二进制 因为我们要使用的是图片下载
content_code = response_code.content
#wb模式将二进制数据写入文件
with open('code.jpg','wb')as fp:
fp.write(content_code)
#获取验证码图片后 下载到本地 然后观察验证码 输入到控制台 给code就可以登录
code_name = input('请输入你的验证码')
#点击登录
url_post = 'https://so.gushiwen.cn/user/login.aspx?from=http%3a%2f%2fso.gushiwen.cn%2fuser%2fcollect.aspx'
data_post = {
'__VIEWSTATE': viewstate,
'__VIEWSTATEGENERATOR': viewstategenerator,
'from': 'http://so.gushiwen.cn/user/collect.aspx',
'email': '17609092650',
'pwd': 'abc8891999',
'code': code_name,
'denglu': '登录'
}
response_post = session.post(url=url,headers=headers,data=data_post)
content_post = response_post.text
with open('gushiwen.html','w',encoding='utf-8') as fp:
fp.write(content_post)
05.scrapy
配置环境
1.创建爬虫项目 scrapy startproject 项目的名字
注意:项目的名字不允许使用数字开头 也不能包含中文
2.创建爬虫文件
(1)要在spiders文件夹中创建爬虫文件
cd 项目名字\项目名字\spiders
cd scrapy_baidu_091\scrapy_baidu_091\spiders
(2)创建爬虫文件
scrapy genspider 爬虫文件的名字 要爬取网页
eg:scrapy genspider baidu http://www.baidu.com
一般情况下不需要添加http协议 因为start——urls的值是根据 allowed_domains修改的 所以添加了http的话 start_urls 就需要我们手动去修改了
3.运行爬虫代码
settings里的ROBOTSTXT_OBEY = True要注释掉
注释掉就不遵守robots协议了 君子协议
运行爬虫:
scrapy crawl 爬虫的名字
eg:scrapy crawl baidu
tips:去掉无关日志信息LOG_LEVEL='ERROR' setting里
框架讲解
import scrapy
class BaiduSpider(scrapy.Spider):
#爬虫的名字 用于运行爬虫的时候 使用的值
name = "baidu"
#允许访问的域名
allowed_domains = ["http://baidu.com"]
#起始的url地址 第一次要访问的域名
#start_urls 是在allowed_domains的前面添加一个http://
# 在allowed_domains后面加/
start_urls = ["https://baidu.com"]
#执行了start_urls之后 执行的方法 方法中response就是返回的那个对象
#相当于 response = urllib.requests.urlopen()
# response = response.get()
def parse(self, response):
#代码
print('我是谁')
#tips 如果连接进去无数据就是xpath路径问题
项目的结构
项目名字
项目名字
spiders文件夹(存储的是爬虫文件)
init
自定义的爬虫文件 核心功能文件 ********
init
items 定义数据结构的地方 爬取的数据包含哪些
middleware 中间件 代理
pipelines 管道 用来处理下载的数据
settings 配置文件 robots协议 ua定义等
response的属性和方法
response.text 获取的是响应的字符串
response.body 获取的是二进制数据
response.xpath 可以直接是xpath方法来解析response中的内容
response.extract( ) 提取seletor对象的data属性值
response.extract_first( ) 提取的seletor列表的第一个数据
架构组成
工作原理
scrapy shell交互终端
Scrapy终端,是一个交互终端,供您在未启动spider的情况下尝试及调试您的爬取代码。 其本意是用来测试提取 数据的代码,不过您可以将其作为正常的Python终端,在上面测试任何的Python代码。 该终端是用来测试XPath或CSS表达式,查看他们的工作方式及从爬取的网页中提取的数据。 在编写您的spider时,该 终端提供了交互性测试您的表达式代码的功能,免去了每次修改后运行spider的麻烦。 一旦熟悉了Scrapy终端后,您会发现其在开发和调试spider时发挥的巨大作用。
进入到scrapy shell的终端 直接在windows的终端中输入scrapy shell 域名
scrapy shell www.baidu.com
scrapy当当网爬取数据
yield语句
- 带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代
- yield 是一个类似 return 的关键字,迭代一次遇到yield时就返回yield后面(右边)的值。重点是:下一次迭代 时,从上一次迭代遇到的yield后面的代码(下一行)开始执行
- 简要理解:yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始
自定义程序
import scrapy
from ..items import ScrapyDangdang95Item
class DangSpider(scrapy.Spider):
name = "dang"
allowed_domains = ["category.dangdang.com"]
start_urls = ["http://category.dangdang.com/cp01.41.70.01.01.00.html"]
#多页爬虫
base_url = 'http://category.dangdang.com/pg'
page = 1
def parse(self, response):
pass
# src= //ul[@id="component_59"]/li//img/@src
# alt= //ul[@id="component_59"]/li//img/@alt
# price=//ul[@id="component_59"]/li//span[@class="search_now_price"]/text()
# 所有的seletor对象 都可以再次调用xpath方法
li_list = response.xpath('//ul[@id="component_59"]/li')
for li in li_list:
src = li.xpath('.//img/@data-original').extract_first()
#第一张没有懒加载 和其他图片的标签属性是不一样的
if src:
src = src
else:
src = li.xpath('.//img/@src').extract_first()
name = li.xpath('.//img/@alt').extract_first()
price = li.xpath('.//span[@class="search_now_price"]/text()').extract_first()
book = ScrapyDangdang95Item(src=src,name=name,price=price)
#获取一个book就将book交给pipelines 返回单个对象
yield book
#每一页爬取的逻辑全是一样的 我们只需要将执行的那个页的请求再次调用parse方法
if self.page < 100:
self.page = self.page + 1
url = self.base_url + str(self.page) + '-cp01.41.70.01.01.00.html'
#怎么调用parse方法
#就是scrapy的get请求
#url就是请求地址 callback就是你要执行的那个函数 注意不加()
yield scrapy.Request(url=url,callback=self.parse)
items数据结构
import scrapy
class ScrapyDangdang95Item(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
#通俗的说你要下载的数据都有什么
src = scrapy.Field()
name = scrapy.Field()
price = scrapy.Field()
pipelines管道
#如果想使用管道的话 那么就必须在settings开启
class ScrapyDangdang95Pipeline:
#在爬虫文件开始之前就执行的方法
def open_spider(self,spider):
self.fp = open('book.json','w',encoding='utf-8')
#item就是yield后面的book对象
def process_item(self, item, spider):
#以下这种模式不推荐 每传递过来一个对象 就打开一次文件 对文件的 操作过于频繁
#(1)write 方法必须要是一个字符串 而不能是其他对象
# with open('book.json','a',encoding='utf-8') as fp:
# fp.write(str(item))
self.fp.write(str(item))
return item
#在爬虫文件执行之后 执行的方法
def close_spider(self,spider):
self.fp.close()
import urllib.request
#多条管道同时开启
# (1)定义管道类
# (2)在settings中开启管道
# "scrapy_dangdang_95.pipelines.DangDangDownloadPipeline":400
class DangDangDownloadPipeline:
def process_item(self, item, spider):
url = 'http:'+ item.get('src')
filename = './books/'+str(item.get('name'))+'.jpg'
urllib.request.urlretrieve(url=url,filename=filename)
return item
多级爬取(meta传递)
import scrapy
from ..items import ScrapyMovie99Item
class MvSpider(scrapy.Spider):
name = "mv"
allowed_domains = ["www.dygod.net"]
start_urls = ["http://www.dygod.net/html/tv/rihantv/index.html"]
# 要第一页的名字 和 第二页的图片
def parse(self, response):
a_list = response.xpath('//ul//a[@class="ulink"]')
for a in a_list:
#获取第一页的name 和 要跳转的链接
name = a.xpath('./text()')
href = a.xpath('./@href').extract_first()
#第二页的地址是
url = 'https://www.dygod.net/' + href
#对第二页链接发起访问
yield scrapy.Request(url=url,callback=self.parse_second,meta={'name':name})
def parse_second(self,response):
src = response.xpath('//div[@id="Zoom"]/img/@src').extract_first()
#接受到请求的那个meta参数的值
name = response.meta['name']
movie = ScrapyMovie99Item(src=src,name=name)
yield movie
crawlspider
CrawlSpider可以定义规则,再解析html内容的时候,可以根据链接规则提取出指定的链接,然后再向这些链接发 送请求
所以,如果有需要跟进链接的需求,意思就是爬取了网页之后,需要提取链接再次爬取,使用CrawlSpider是非常合适的
日志信息
日志级别:
CRITICAL:严重错误
ERROR: 一般错误
WARNING: 警告
INFO: 一般信息
DEBUG: 调试信息
默认的日志等级是DEBUG 只要出现了DEBUG或者DEBUG以上等级的日志 那么这些日志将会打印
#指定日志级别
LOG_LEVEL = 'WARING'
#日志文件存储在logdemo.log的文件中
LOG_FILE = 'logdemo.log'
scrapy的post请求
class Tset(scrapy.Spider):
name = 'testpost'
allowed_domains = ['https://fanyi.baidu.com/sug']
#post请求 没有参数就无意义
#start_urls 和 parse 都没用了
def start_requests(self):
url = 'https://fanyi.baidu.com/sug'
data = {
'kw':'final'
}
yield scrapy.FormRequest(url=url,formdata=data,
callback=self.parse_second)
def parse_second(self,response):
content = response.text
obj = json.loads(content,encoding='utf-8')
代理
(1)到settings.py中,打开一个选项
DOWNLOADER_MIDDLEWARES = {
'postproject.middlewares.Proxy': 543,
}
(2)到middlewares.py中写代码
def process_request(self, request, spider):
request.meta['proxy'] = 'https://113.68.202.10:9999'
return Non
06.Python基础
爬虫环境配置与python基础语法
更多推荐
所有评论(0)