我的编程空间,编程开发者的网络收藏夹
学习永远不晚

爬虫学习

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

爬虫学习

Jupyter环境安装

安装Anaconda(集成环境), 安装成功后能够提供一种基于浏览器的可视化工具 ---Jupyter.

什么是jupyter notebook:

Jupyter Notebook是以网页的形式打开,可以在网页页面中直接编写代码和运行代码,代码的运行结果也会直接在代码块下显示。如在编程过程中需要编写说明文档,可在同一个页面中直接编写,便于作及时的说明和解释.

jupyter notebook 的主要特点:

1, 编程时具有语法高亮, 缩进,tab补全的功能;

2, 可直接通过浏览器运行代码, 同时在代码块下方展示运行结果;

3, 对代码编写说明文档或语句时, 支持Markdown语法.

安装 jupyter notebook :

安装 jupyter notebook 的前提是需要安装了Python(3.3或2.7以上版本)

通过安装Anaconda来解决Jupyter Notebook的安装问题,因为Anaconda已经自动为你安装了Jupter Notebook及其他工具,还有python中超过180个科学包及其依赖项.

通常Anaconda 发行版已经自动安装了jupyter notebook, 若没有安装, 可以在Windows的Anaconda prompt / macOS的终端中输入安装命令:

conda install jupyter notebook

运行jupyter notebook

默认端口: 8888

cmd 命令行中的指令

-- 在本文件路径下输入: jupyter notebook---开启jupyter服务

浏览器会自动开启jupyter, 其中 ' / ' 表示的根目录是文件夹的目录

浏览器默认显示: http://localhost:8888 localhost 指的是本机, 8888 则是端口号.

注意: 开启服务后, 在操作jupyter notebook 时不能关闭终端, 否则就会断开与本地服务器的链接.

指定端口启动:

自定义端口启动jupyter notebook 可以在终端输入以下命令:

jupyter notebook -port port_number

其中 port_number 是自定义端口号, 直接以数字的形式写在命令中.

启动服务器不打开浏览器:

若想要启动jupyter notebook 但是不打算立即进入到主页面, 就无需立刻启动浏览器:

jupyter notebook -no-browser

此时,将会在终端显示启动的服务器信息,并在服务器启动之后,显示出打开浏览器页面的链接。当你需要启动浏览器页面时,只需要复制链接,并粘贴在浏览器的地址栏中,轻按回车变转到了你的Jupyter Notebook页面。

快捷键:

1, 向上插入一个cell: a

2, 向下插入一个cell: b

3, 删除cell: x

4, 将code切换成markdown: m

5, 将markdown切换成code: y

6, 运行cell: shift+enter

7, 查看帮助文档: shift+tab

8, 自动提示: tab

9, 在markdown中 # 可以控制字体大小, 可以使用HTML标签更改样式颜色; 在code中, 一个源文件内的代码没有上下之分.

 

爬虫

是通过编写程序, 模拟浏览器上网, 然后让其去互联网上爬取数据的过程.

分类:

增量式:

聚焦爬虫:

增量式爬虫:

反爬机制与反反爬策略

反爬:

1, robots.txt协议

2, UA

3, 数据加密

4, 懒加载

5, 代理ip

 

http和https协议:

抓包工具:

request模块

代码编写流程:

1, 指定url

2, 发起请求

3, 获取响应对象中的数据

4, 持久化存储

import requests
url = 'https://www.sogou.com/'
response_obj = requests.get(url=url)
page_text = response_obj.text
with open('./sougou.html', 'w', encoding='utf-8')as fp:
  fp.write(page_text)

 

案例1:

爬取搜狗浏览器中的词条搜索信息

# import requests
# url = 'https://www.sogou.com/web'
# # 封装参数
# can_shu = input('enter a word:')
# param = {
#     'query': can_shu
# }
# response_obj = requests.get(url=url, params=param)
# page_text = response_obj.content
# fileName = can_shu+'.html'
# with open(fileName, 'wb')as fp:
#     fp.write(page_text)
#     print('over')

 

案例2:

爬取百度翻译结果

# 案例2 爬取百度翻译结果
# 注意: 翻译的结果是局部刷新, 采用ajax异步请求
import requests
# post 请求
url = 'https://fanyi.baidu.com/sug'
can_shu = input('worlds:')
data = {
  'kw': can_shu
}
response_obj = requests.post(url=url, data=data)
# 返回的response对象以json数据类型展示.若以text形式为字符串, 若以content形式为二进制.
print(response_obj.json())

 

案例3:

爬取豆瓣电影的详情数据

from requests
# get 请求
url = 'https://movie.douban.com/j/chart/top_list'
# 动态捕获电影, 设置一个url字典
param = {
  "type": "5",
"interval_id": "100:90",
"action": "",
"start": "0", # 表示从第'0'索引位置开始
"limit": "1" # 表示爬取一个
}
# 返回一个列表
move_data = requests.get(url=url, params=Parma).json()
print(move_data)

 

案例4:

爬取化妆品公司的生产许可证相关信息

# 案例4
# 反扒机制: UA检测 --> 反反爬策略UA伪装.
# --- 请求载体的身份标识: User-Agent.请求载体不一样, 标识就不一样.基于浏览器和爬虫
#     的请求在意不一样, 所以需要伪装成某一浏览器请求.
import requests
id_list = []
# post 请求
url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'

}
# 爬取多页
for page in range(1, 3):
data = {
'on': 'true',
'page': str(page),
'pageSize': '15',
'productName': '',
'conditionType': '1',
'applyname': '',
'applysn': ''
}
data_obj = requests.post(url=url, data=data, headers=headers).json()
# 获取各个ID值
for dic in data_obj['list']:
id = dic['ID']
id_list.append(id)
print(id_list)

# 通过ID 获取各个公司的生产许可证相关信息
detail_url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById'
for id in id_list:
detail_data = {
'id':id
}
detail_json = requests.post(url=detail_url, data=detail_data, headers=headers).json()
print(detail_json)

 

案例5:

爬取图片

# 爬取图片
import requests
url = 'http://d.ifengimg.com/w640_q75/p0.ifengimg.com/pmop/2018/0923/D7D76D3B007F024D2D0964DFE3AD909A68232483_size561_w1080_h1920.jpeg'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'

}
# 图片为二进制数据,可以用content
img_data = requests.get(url=url, headers=headers).content
with open('./gua_jie.jpg', 'wb') as fp:
  fp.write(img_data)

 

案例6:

正则解析爬取动态加载的图片

re.M 表示将正则依次做用于每行;

re.S 表示将正则作用于原数据(整体)

# 爬取动态加载的图片
import requests
import re
import urllib
import os
# 拿到指定页码的图片
url = 'https://www.qiushibaike.com/pic/page/%d/?s=5171142'
start_page = int(input('start page'))
end_page = int(input('end page'))
headers = {
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
}
if not os.path.exists('./qiutu'):
  os.mkdir('./qiutu')
for page in range(start_page, end_page):
  new_url = format(url%page)
  page_text = requests.get(url=new_url, headers=headers).text
  # 提取图片的class="lazy" data-src属性
  img_url_list = re.findall('<div class="thumb">.*?<img class="lazy" data-src="(.*?)" alt=.*?</div>', page_text, re.S)
  # 根据class="lazy" data-src属性爬取纯图片
  for img_url in img_url_list:
      img_url = 'http:'+img_url
      imgName = img_url.split('/')[-1]
      imgPath ='qiutu/'+imgName
      urllib.request.urlretrieve(url=img_url, filename=imgPath)
      print('well done!')
print('完成!!!')

 

bs4模块

环境安装:

pip3 install bs4

pip3 install lxml

解析原理:

1, 将即将要进行解析的源码加载到bs对象

2, 调用bs对象中相关的方法或属性进行源码中的相关标签的定位(锁定即将解析的源码)

3, 将定位到的标签之间存在的文本或属性值获取到(源码中的有用数据)

 

案例1:

下载各个章节名称及其下的文本内容

# bs4模块
from bs4 import BeautifulSoup
import requests
url = 'http://www.shicimingju.com/book/rulinwaishi.html'
headers = {
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
}
page_text = requests.get(url=url, headers=headers).text
# 加载要解析的源码   lxml 为解析器
soup = BeautifulSoup(page_text, 'lxml')
# 进行标签定位
a_list = soup.select('.book-mulu>ul>li>a')
fp = open('儒林外史.txt', 'w', encoding='utf-8')
# 获取到标签之间的有用数据, 并通过该数据下载想要所取得的内容
for a in a_list:
  title = a.string
  detail_url ='http://www.shicimingju.com'+a['href']
  detail_page_text = requests.get(url=detail_url, headers=headers).text
   
  soup = BeautifulSoup(detail_page_text, 'lxml')
  content = soup.find('div', class_='chapter_content').text

  fp.write(title+'\n'+content)
  print(title, '下载完毕')
print('well done!!')
fp.close()

 

xpath模块:

环境安装: pip install lxml

xpath 常用表达式:

/ 表示一种层级关系

@ 表示属性定位

图中p[1] 表示 p 标签中的第一个 p 标签.

解析原理:

1, 获取页面源码数据

2, 实例化一个etree的对象, 并且将页面源码数据加载到该对象中

3, 调用该对象的xpath方法进行指定标签定位

注意: xpath函数必须结合xpath表达式进行标签定位和内容捕获

案例1:

获取房源信息

# xpath模块爬取二手房信息

import requests
from lxml import etree

url = 'https://xy.58.com/ershoufang/?PGTID=0d000000-0000-00d2-8801-ee7a9683ca0f&ClickID=2/'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
}
# 获取页面源码数据
page_text = requests.get(url=url, headers=headers).text
# 实例化对象
tree = etree.HTML(page_text)
# li_list 的类型为Element 类型的列表对象
# 标签定位及内容捕获
li_list = tree.xpath('//ul[@class="house-list-wrap"]/li')
fp = open('fang.csv', 'w', encoding='utf-8')
for li in li_list:
  # 进行局部解析要加 '.'
  xin_xi = li.xpath('./div[2]/p[1]//text()')[1]
  price = li.xpath('./div[3]//text()')
  price = ''.join(price)
  fp.write(xin_xi+":"+price+"\n")
fp.close()
print('well done!!')

 

案例2:

获取图片有效信息

# 案例2
# 解析图片
import requests
from lxml import etree
import os
import urllib

url = 'http://pic.netbian.com/4kdongman/index_2.html'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'

}
response = requests.get(url=url, headers=headers)
if not os.path.exists('./imgs'):
  os.mkdir('./imgs')
page_text = response.text
tree = etree.HTML(page_text)
print(tree)
li_list = tree.xpath('//div[@class="slist"]/ul/li')
print(li_list)
for li in li_list:
  img_name = li.xpath('./a/b/text()')[0]
  # 处理中文乱码
  img_name.encode('iso-8859-1').decode('gbk')
  img_url = 'http://pic.netbian.com'+li.xpath('./a/img/@class="lazy" data-src')[0]
  print(img_name)
  img_path = './img'+img_name+'.jpg'
  urllib.request.urlretrieve(url=img_url, filename=img_path)
  print(img_path, 'nice!!')
print('over!!')

 

案例3:

煎蛋网图片下载

当数据加密时(防盗图),需要解密爬取.

案例4:

爬去免费简历模板

# 爬取站长素材的简历模板
import random
import requests
from lxml import etree
headers ={
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'

}
url = 'http://sc.chinaz.com/jianli/free_%d.html'
for page in range(1, 4):
  if page == 1:
      new_url = 'http://sc.chinaz.com/jianli/free.html'
  else:
      new_url = format(url%page)
# 获取源码数据
response = requests.get(url=new_url, headers=headers)
response.encoding = 'utf-8'
page_text = response.text
# 实例化etree对象
tree = etree.HTML(page_text)
# 定位标签
div_list = tree.xpath('//div[@id="container"]/div')
for div in div_list:
  detail_url = div.xpath('./a/@href')[0]
  name = div.xpath('./a/img/@alt')[0]
  detail_page = requests.get(url=detail_url, headers=headers).text
  tree = etree.HTML(detail_page)
  # 锁定下载地址
  down_list = tree.xpath('//div[@class="clearfix mt20 downlist"]/ul/li/a/@href')
  # 随机选取一个下载地址
  down_url = random.choice(down_list)
  # 获取到下载内容的压缩包
  data = requests.get(url= detail_url, headers=headers).content
  fileName = name+'.rar'
  with open(fileName, 'wb') as fp:
      fp.write(data)
      print('下载成功!!')

注意:​

解决方法:
1, 当请求成功后马上断开该次请求. 为了及时释放请求池资源,
    ---- 'connection': 'close'
  若首次执行任然报错, 那就再次执行代码.
2, 使用代理ip
3, 使用sleep
案例5:

爬取城市名称

# 解析所有的城市名称
import requests
from lxml import etree
headers = {

}
# 明确要爬取数据的url地址
url = 'https://www.aqistudy.cn/historydata/'
# 确定要爬取的整体数据信息
page_text = requests.get(url=url, headers=headers).text
# 把要爬取的数据生成在etree对象中
tree = etree.HTML(page_text)
# 锁定要爬取信息的具体页面标签, '|'该管道符表示左边成立则执行右边,管道符左右都要空格.
li_list = tree.xpath('//div[@class="bottom"]/ul/li | //div[@class="bottom"]/ul/div[2]/li')
for li in li_list:
  city_name = li.xpath('./a/text()')[0]
  print(city_name)
案例6:

图片懒加载;:

# 图片懒加载(一种反爬机制)
# 首先排除动态加载和url加密, 直接在Elements中找.
# 当图片还未在可视化范围内时, 图片标签是'class="lazy" data-src2', 加载后为'class="lazy" data-src',
# class="lazy" data-src2 是一个伪属性, 在爬取图片时可以直接用'class="lazy" data-src2'作为标签, 无需考虑是否在可视化范围内.
案例7:

代理ip:

# 请求过于频繁, 有被封ip的风险, 可以使用代理ip
# 代理ip的类型必须要和请求url的协议头保持一致
import requests
url = 'https://www.baidu.com/s?cl=3&wd=ip'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
}
# proxies后为代理ip的键值对
page_text = requests.get(url=url, headers=headers, proxies={'https': '103.203.133.250:8080'}).text
with open('./ip.html', 'w', encoding='utf-8')as fp:
  fp.write(page_text)

 

案例8 验证码

借助云打码平台

注册普通用户和开发者用户

登录:

登录普通用户

登录开发者用户

创建一个软件: 我的软件->创建软件

下载示例代码: 在开发者中心下载最新的DLL(PythonHttp示例下载)

在示例代码中录入普通用户名及密码等相关变量值.

再编写爬虫代码

案例9:模拟登陆

案例10:

动态数据加载(selenium):

环境安装: pip install selenium

编码流程:

导包:

from selenium import webdriver
from time import sleep
# 需要借助浏览器终端的驱动程序, 创建浏览器对象
bro = webdriver.Chrome(executable_path=r'D:\chromedriver\chromedriver.exe')
# 标明要使用的浏览器
bro.get(url='https://www.baidu.com/')
# 明确搜索框位置
text_input = bro.find_element_by_id('kw')
# 确定搜索框内要搜索的内容
text_input.send_keys('美少女战士')
# 点击搜索
bro.find_element_by_id('su').click()
sleep(4)
# 获取当前页面的源码数据(包括动态加载的数据)
print(bro.page_source)
# 退出
bro.quit()
# 获取更多的详情数据
from selenium import webdriver
from time import sleep
url = '想要获得数据的页面详细地址'
# 调用驱动程序
bro = webdriver.Chrome(executable_path=r'D:\chromedriver\chromedriver.exe')
bro.get(url)
sleep(3)
# 页面向下滚动的js代码(有些页面数据是在页面向下滚动时才刷新出来的)
bro.execute_script('window.scrollTo(0, document.body.scrollHeight)')
sleep(3)
bro.execute_script('window.scrollTo(0, document.body.scrollHeight)')
sleep(2)
# 拿到所有页面数据
page_text = bro.page_source
with open('./douban.html', 'w',encoding='utf-8')as fp:
  fp.write(page_text)
sleep(2)
bro.quit()

注意: PhantomJS是一个无界面的浏览器 webdriver.PhantomJS​

 

线程池

from multiprocessing .dummy import Pool

可以设置多个线程池, 同时爬取多个任务

 

移动端数据爬取

 

scrapy框架:

Scrapy框架是一个为了爬取网页数据, 提取结构性数据而编写的应用框架. 所谓框架就是一个已经继承各种功能(高性能异步下载, 队列, 分布式, 解析, 持久化等)的具有很强通用性的项目模板.

安装

linux: pip3 install scrapy

Windows: 1, pip3 install wheel

2, 下载twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted

3, 进入下载目录, 执行 pip3 install Twisted- 17.1 - 0 -cp36-cp36m-win_amd64.whl

4, pip3 install pywin32

5, pip3 install scrapy

基础使用

1, 创建项目:

scrapy startproject 项目名

项目目录:

spiders(爬虫文件) 的作用: url的指定; 请求的发送; 进行数据解析; item管道的提交

items 文件: 只要涉及持久化存储的相关的操作, 必须要卸载管道文件

pipelines文件(管道文件): 需要接受爬虫文件提交过来的数据, 并对数据进行持久化存储.

2, 创建爬虫文件:

先进入项目内--- scrapy genspider 爬虫文件名 爬取的起始url

如:

执行爬虫文件: 在终端中输入--- scrapy crawl 爬虫文件名 (此时会把日志文件一起输出, 若不输出日志文件, 在后面追加 '--nolog' )

当ROBOTS反爬协议生效时, 不能输出response结果, 此时可以更改设置中的协议为Flase

当UA反爬机制生效时也不能输出结果, 那么就需要更改设置, 甚至替换请求载体的身份标识.

# -*- coding: utf-8 -*-
import scrapy

# 该文件作用是进行数据的爬取和解析
class FirstSpider(scrapy.Spider):
  # 爬虫文件的名称: 根据爬虫名称可以定位到指定的爬虫文件
  name = 'first'
  # 允许的域名
  allowed_domains = ['www.baidu.com']
  # 起始URL列表(要爬取的url地址必须在允许的域名下,为了不冲突也可以注释掉域名)
  start_urls = ['https://www.baidu.com/']

  # 用于解析: response就是起始URL对应的对象,每执行一次起始url列表中的url,就会调用一次该方法.
  def parse(self, response):
      print(response)
3. 基于终端指令的持久化存储
  • 保证爬虫文件的parse方法中有可迭代类型对象(通常为列表or字典)的返回,该返回值可以通过终端指令的形式写入指定格式的文件中进行持久化操作。

执行输出指定格式进行存储:将爬取到的数据写入不同格式的文件中进行存储
  scrapy crawl 爬虫名称 -o xxx.json
  scrapy crawl 爬虫名称 -o xxx.xml
  scrapy crawl 爬虫名称 -o xxx.csv

 

# -*- coding: utf-8 -*-
import scrapy

# 该文件作用是进行数据的爬取和解析
class FirstSpider(scrapy.Spider):
  # 爬虫文件的名称: 根据爬虫名称可以定位到指定的爬虫文件
  name = 'first'
  # 允许的域名
  # allowed_domains = ['www.baidu.com']
  # 起始URL列表(要爬取的url地址必须在允许的域名下,为了不冲突也可以注释掉域名)
  start_urls = ['https://www.qiushibaike.com/text/']

  # 用于解析: response就是起始URL对应的对象,每执行一次起始url列表中的url
  # 就会调用一次该方法.
  def parse(self, response):
      all_data = []
      # xpath 返回的列表元素类型是Select类型
      div_list = response.xpath('//div[@id="content-left"]/div')
      for div in div_list:
          title = div.xpath('./div[1]/a[2]/h2/text() | ./div/span[2]/h2/text()')[0].extract()
          # 如果能保证列表内只有一个元素, 可以用extract_first
          # title = div.xpath('./div[1]/a[2]/h2/text() | ./div/span[2]/h2/text()').extract_first()
          print(title)
          content = div.xpath('./a/div/span/text()').extract()
          # 该种情况不能往数据库中存储
          dic = {
              'title': title,
              'content': content
          }
          all_data.append(dic)
  # 基于终端指令的持久化存储: 可以通过终端指令的形式将parse方法的返回 值中存储的数据进行本地磁盘的持久化存储.
      return all_data

基于终端指令的存储命令:

4.基于管道的持久化存储

scrapy框架中已经为我们专门集成好了高效、便捷的持久化操作功能,我们直接使用即可。要想使用scrapy的持久化操作功能,我们首先来认识如下两个文件:

    items.py:数据结构模板文件。定义数据属性。
  pipelines.py:管道文件。接收数据(items),进行持久化操作。

持久化流程:
  1.爬虫文件爬取到数据后,需要将数据封装到items对象中。
  2.使用yield关键字将items对象提交给pipelines管道进行持久化操作。
  3.在管道文件中的process_item方法中接收爬虫文件提交过来的item对象,然后编写持久化存储的代码将item对象中存储的数据进行持久化存储
  4.settings.py配置文件中开启管道

将糗事百科首页中的段子和作者数据爬取下来,然后进行持久化存储

- 爬虫文件:qiubaiDemo.py

# -*- coding: utf-8 -*-
import scrapy
from secondblood.items import SecondbloodItem

class QiubaidemoSpider(scrapy.Spider):
   name = 'qiubaiDemo'
   allowed_domains = ['www.qiushibaike.com']
   start_urls = ['http://www.qiushibaike.com/']

   def parse(self, response):
       odiv = response.xpath('//div[@id="content-left"]/div')
       for div in odiv:
           # xpath函数返回的为列表,列表中存放的数据为Selector类型的数据。我们解析到的内容被封装在了Selector对象中,需要调用extract()函数将解析的内容从Selecor中取出。
           author = div.xpath('.//div[@class="author clearfix"]//h2/text()').extract_first()
           author = author.strip('\n')#过滤空行
           content = div.xpath('.//div[@class="content"]/span/text()').extract_first()
           content = content.strip('\n')#过滤空行

           #将解析到的数据封装至items对象中
           item = SecondbloodItem()
           item['author'] = author
           item['content'] = content

           yield item#提交item到管道文件(pipelines.py)

- items文件:items.py

import scrapy


class SecondbloodItem(scrapy.Item):
   # define the fields for your item here like:
   # name = scrapy.Field()
   author = scrapy.Field() #存储作者
   content = scrapy.Field() #存储段子内容

- 管道文件:pipelines.py

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html


class SecondbloodPipeline(object):
   #构造方法
   def __init__(self):
       self.fp = None  #定义一个文件描述符属性
  #下列都是在重写父类的方法:
   #开始爬虫时,执行一次
   def open_spider(self,spider):
       print('爬虫开始')
       self.fp = open('./data.txt', 'w')

   #因为该方法会被执行调用多次,所以文件的开启和关闭操作写在了另外两个只会各自执行一次的方法中。
   def process_item(self, item, spider):
       #将爬虫程序提交的item进行持久化存储
       self.fp.write(item['author'] + ':' + item['content'] + '\n')
       return item

   #结束爬虫时,执行一次
   def close_spider(self,spider):
       self.fp.close()
       print('爬虫结束')

- 配置文件:settings.py

#开启管道
ITEM_PIPELINES = {
   'secondblood.pipelines.SecondbloodPipeline': 300, #300表示为优先级,值越小优先级越高
}
5. 基于mysql的管道存储

在管道文件里将item对象中的数据值存储到了磁盘中,如果将item数据写入mysql数据库的话,只需要将上述案例中的管道文件修改成如下形式:

- pipelines.py文件

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html

#导入数据库的类
import pymysql
class QiubaiproPipelineByMysql(object):

   conn = None  #mysql的连接对象声明
   cursor = None#mysql游标对象声明
   def open_spider(self,spider):
       print('开始爬虫')
       #链接数据库
       self.conn = pymysql.Connect(host='127.0.0.1',port=3306,user='root',password='123456',db='qiubai')
   #编写向数据库中存储数据的相关代码
   def process_item(self, item, spider):
       #1.链接数据库
       #2.执行sql语句
       sql = 'insert into qiubai values("%s","%s")'%(item['author'],item['content'])
       self.cursor = self.conn.cursor()
       #执行事务
       try:
           self.cursor.execute(sql)
           self.conn.commit()
       except Exception as e:
           print(e)
           self.conn.rollback()

       return item
   def close_spider(self,spider):
       print('爬虫结束')
       self.cursor.close()
       self.conn.close()

settings.py

ITEM_PIPELINES = {
   'qiubaiPro.pipelines.QiubaiproPipelineByMysql': 300,
}

 

6. 基于redis的管道存储

在管道文件里将item对象中的数据值存储到了磁盘中,如果将item数据写入redis数据库的话,只需要将上述案例中的管道文件修改成如下形式:

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html

import redis

class QiubaiproPipelineByRedis(object):
   conn = None
   def open_spider(self,spider):
       print('开始爬虫')
       #创建链接对象
       self.conn = redis.Redis(host='127.0.0.1',port=6379)
   def process_item(self, item, spider):
       dict = {
           'author':item['author'],
           'content':item['content']
      }
       #写入redis中
       self.conn.lpush('data', dict)
       return item

- pipelines.py文件

ITEM_PIPELINES = {
   'qiubaiPro.pipelines.QiubaiproPipelineByRedis': 300,
}

面试题:如果最终需要将爬取到的数据值一份存储到磁盘文件,一份存储到数据库中,则应该如何操作scrapy?  

- 答:管道文件中的代码为

#该类为管道类,该类中的process_item方法是用来实现持久化存储操作的。
class DoublekillPipeline(object):

   def process_item(self, item, spider):
       #持久化操作代码 (方式1:写入磁盘文件)
       return item

#如果想实现另一种形式的持久化操作,则可以再定制一个管道类:
class DoublekillPipeline_db(object):

   def process_item(self, item, spider):
       #持久化操作代码 (方式1:写入数据库)
       return item

在settings.py开启管道操作代码为:

#下列结构为字典,字典中的键值表示的是即将被启用执行的管道文件和其执行的优先级。
ITEM_PIPELINES = {
  'doublekill.pipelines.DoublekillPipeline': 300,
   'doublekill.pipelines.DoublekillPipeline_db': 200,
}

#上述代码中,字典中的两组键值分别表示会执行管道文件中对应的两个管道类中的process_item方法,实现两种不同形式的持久化操作。

 

7. 递归爬取解析多页页面数据

- 需求:将糗事百科所有页码的作者和段子内容数据进行爬取切持久化存储

- 需求分析:每一个页面对应一个url,则scrapy工程需要对每一个页码对应的url依次发起请求,然后通过对应的解析方法进行作者和段子内容的解析。

实现方案:

1.将每一个页码对应的url存放到爬虫文件的起始url列表(start_urls)中。(不推荐)

2.使用Request方法手动发起请求。(推荐)

代码展示:

# -*- coding: utf-8 -*-
import scrapy
from qiushibaike.items import QiushibaikeItem
# scrapy.http import Request
class QiushiSpider(scrapy.Spider):
   name = 'qiushi'
   allowed_domains = ['www.qiushibaike.com']
   start_urls = ['https://www.qiushibaike.com/text/']

   #爬取多页
   pageNum = 1 #起始页码
   url = 'https://www.qiushibaike.com/text/page/%s/' #每页的url

   def parse(self, response):
       div_list=response.xpath('//*[@id="content-left"]/div')
       for div in div_list:
           #//*[@id="qiushi_tag_120996995"]/div[1]/a[2]/h2
           author=div.xpath('.//div[@class="author clearfix"]//h2/text()').extract_first()
           author=author.strip('\n')
           content=div.xpath('.//div[@class="content"]/span/text()').extract_first()
           content=content.strip('\n')
           item=QiushibaikeItem()
           item['author']=author
           item['content']=content

           yield item #提交item到管道进行持久化

        #爬取所有页码数据
       if self.pageNum <= 13: #一共爬取13页(共13页)
           self.pageNum += 1
           url = format(self.url % self.pageNum)

           #递归爬取数据:callback参数的值为回调函数(将url请求后,得到的相应数据继续进行parse解析),递归调用parse函数
           yield scrapy.Request(url=url,callback=self.parse)

8. 五大核心组件工作流程:

  • 引擎(Scrapy) 用来处理整个系统的数据流处理, 触发事务(框架核心)

  • 调度器(Scheduler) 用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址

  • 下载器(Downloader) 用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)

  • 爬虫(Spiders) 爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面

  • 项目管道(Pipeline) 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。

9. post请求发送

- 问题:在之前代码中,我们从来没有手动的对start_urls列表中存储的起始url进行过请求的发送,但是起始url的确是进行了请求的发送,那这是如何实现的呢?

- 解答:其实是因为爬虫文件中的爬虫类继承到了Spider父类中的start_requests(self)这个方法,该方法就可以对start_urls列表中的url发起请求:

  def start_requests(self):
       for u in self.start_urls:
          yield scrapy.Request(url=u,callback=self.parse)

【注意】该方法默认的实现,是对起始的url发起get请求,如果想发起post请求,则需要子类重写该方法。

  -方法: 重写start_requests方法,让其发起post请求:

def start_requests(self):
       #请求的url
       post_url = 'http://fanyi.baidu.com/sug'
       # post请求参数
       formdata = {
           'kw': 'wolf',
      }
       # 发送post请求
       yield scrapy.FormRequest(url=post_url, formdata=formdata, callback=self.parse)

 

10. Scrapy的日志等级

  - 在使用scrapy crawl spiderFileName运行程序时,在终端里打印输出的就是scrapy的日志信息。

  - 日志信息的种类:

        ERROR : 一般错误

        WARNING : 警告

        INFO : 一般的信息

        DEBUG : 调试信息

       

  - 设置日志信息指定输出:

    在settings.py配置文件中,加入

LOG_LEVEL = ‘指定日志信息种类’即可。

LOG_FILE = 'log.txt'则表示将日志信息写入到指定文件中进行存储。

11. 请求传参

  - 在某些情况下,我们爬取的数据不在同一个页面中,例如,我们爬取一个电影网站,电影的名称,评分在一级页面,而要爬取的其他电影详情在其二级子页面中。这时我们就需要用到请求传参。

  - 案例展示:爬取www.id97.com电影网,将一级页面中的电影名称,类型,评分一级二级页面中的上映时间,导演,片长进行爬取。

  爬虫文件:

# -*- coding: utf-8 -*-
import scrapy
from moviePro.items import MovieproItem

class MovieSpider(scrapy.Spider):
   name = 'movie'
   allowed_domains = ['www.id97.com']
   start_urls = ['http://www.id97.com/']

   def parse(self, response):
       div_list = response.xpath('//div[@class="col-xs-1-5 movie-item"]')

       for div in div_list:
           item = MovieproItem()
           item['name'] = div.xpath('.//h1/a/text()').extract_first()
           item['score'] = div.xpath('.//h1/em/text()').extract_first()
           #xpath(string(.))表示提取当前节点下所有子节点中的数据值(.)表示当前节点
           item['kind'] = div.xpath('.//div[@class="otherinfo"]').xpath('string(.)').extract_first()
           item['detail_url'] = div.xpath('./div/a/@href').extract_first()
           #请求二级详情页面,解析二级页面中的相应内容,通过meta参数进行Request的数据传递
           yield scrapy.Request(url=item['detail_url'],callback=self.parse_detail,meta={'item':item})

   def parse_detail(self,response):
       #通过response获取item
       item = response.meta['item']
       item['actor'] = response.xpath('//div[@class="row"]//table/tr[1]/a/text()').extract_first()
       item['time'] = response.xpath('//div[@class="row"]//table/tr[7]/td[2]/text()').extract_first()
       item['long'] = response.xpath('//div[@class="row"]//table/tr[8]/td[2]/text()').extract_first()
       #提交item到管道
       yield item

 items文件:

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class MovieproItem(scrapy.Item):
   # define the fields for your item here like:
   name = scrapy.Field()
   score = scrapy.Field()
   time = scrapy.Field()
   long = scrapy.Field()
   actor = scrapy.Field()
   kind = scrapy.Field()
   detail_url = scrapy.Field()

管道文件:

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html

import json
class MovieproPipeline(object):
   def __init__(self):
       self.fp = open('data.txt','w')
   def process_item(self, item, spider):
       dic = dict(item)
       print(dic)
       json.dump(dic,self.fp,ensure_ascii=False)
       return item
   def close_spider(self,spider):
       self.fp.close()

12. 如何提高scrapy的爬取效率
增加并发:
  默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发设置成了为100。

降低日志级别:
  在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:LOG_LEVEL = ‘INFO’

禁止cookie:
  如果不是真的需要cookie,则在scrapy爬取数据时可以进制cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:COOKIES_ENABLED = False

禁止重试:
  对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:RETRY_ENABLED = False

减少下载超时:
  如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:DOWNLOAD_TIMEOUT = 10 超时时间为10s

测试案例:爬取校花网校花图片 www.521609.com

# -*- coding: utf-8 -*-
import scrapy
from xiaohua.items import XiaohuaItem

class XiahuaSpider(scrapy.Spider):

   name = 'xiaohua'
   allowed_domains = ['www.521609.com']
   start_urls = ['http://www.521609.com/daxuemeinv/']

   pageNum = 1
   url = 'http://www.521609.com/daxuemeinv/list8%d.html'

   def parse(self, response):
       li_list = response.xpath('//div[@class="index_img list_center"]/ul/li')
       for li in li_list:
           school = li.xpath('./a/img/@alt').extract_first()
           img_url = li.xpath('./a/img/@class="lazy" data-src').extract_first()

           item = XiaohuaItem()
           item['school'] = school
           item['img_url'] = 'http://www.521609.com' + img_url

           yield item

       if self.pageNum < 10:
           self.pageNum += 1
           url = format(self.url % self.pageNum)
           #print(url)
           yield scrapy.Request(url=url,callback=self.parse)

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class XiaohuaItem(scrapy.Item):
   # define the fields for your item here like:
   # name = scrapy.Field()
   school=scrapy.Field()
   img_url=scrapy.Field()

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html

import json
import os
import urllib.request
class XiaohuaPipeline(object):
   def __init__(self):
       self.fp = None

   def open_spider(self,spider):
       print('开始爬虫')
       self.fp = open('./xiaohua.txt','w')

   def download_img(self,item):
       url = item['img_url']
       fileName = item['school']+'.jpg'
       if not os.path.exists('./xiaohualib'):
           os.mkdir('./xiaohualib')
       filepath = os.path.join('./xiaohualib',fileName)
       urllib.request.urlretrieve(url,filepath)
       print(fileName+"下载成功")

   def process_item(self, item, spider):
       obj = dict(item)
       json_str = json.dumps(obj,ensure_ascii=False)
       self.fp.write(json_str+'\n')

       #下载图片
       self.download_img(item)
       return item

   def close_spider(self,spider):
       print('结束爬虫')
       self.fp.close()

配置文件:

USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# Configure maximum concurrent requests performed by Scrapy (default: 16)
CONCURRENT_REQUESTS = 100
COOKIES_ENABLED = False
LOG_LEVEL = 'ERROR'
RETRY_ENABLED = False
DOWNLOAD_TIMEOUT = 3
# Configure a delay for requests for the same website (default: 0)
# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
# The download delay setting will honor only one of:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16
DOWNLOAD_DELAY = 3

 

13. scrapy中的selenium

未完......

 

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

爬虫学习

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

爬虫学习

Jupyter环境安装安装Anaconda(集成环境), 安装成功后能够提供一种基于浏览器的可视化工具 ---Jupyter.什么是jupyter notebook:Jupyter Notebook是以网页的形式打开,可以在网页页面中直接编
2023-01-30

『爬虫』学习记录

## 在学习爬虫中遇到很多坑,写出来供道友参考出现诸如以下错误    ModuleNotFoundError: No module named 'js2xml'    NameError: name 'js2xml' is not defi
2023-01-31

【python爬虫学习 】python

pip 安装 pip install scrapy可能的问题: 问题/解决:error: Microsoft Visual C++ 14.0 is required.实例demo教程 中文教程文档 第一步:创建项目目录scrapy
2023-01-31

Python爬虫学习路线

(一)如何学习Python学习Python大致可以分为以下几个阶段:1.刚上手的时候肯定是先过一遍Python最基本的知识,比如说:变量、数据结构、语法等,基础过的很快,基本上1~2周时间就能过完了,我当时是在这儿看的基础:Python 简
2023-01-31

Python 爬虫学习笔记之多线程爬虫

XPath 的安装以及使用 1 . XPath 的介绍 刚学过正则表达式,用的正顺手,现在就把正则表达式替换掉,使用 XPath,有人表示这太坑爹了,早知道刚上来就学习 XPath 多省事 啊。其实我个人认为学习一下正则表达式是大有益处的,
2022-06-04

爬虫学习之第四章爬虫进阶之多线程爬虫

有些时候,比如下载图片,因为下载图片是一个耗时的操作。如果采用之前那种同步的方式下载。那效率肯会特别慢。这时候我们就可以考虑使用多线程的方式来下载图片。多线程介绍:多线程是为了同步完成多项任务,通过提高资源使用效率来提高系统的效率。线程是在
2023-01-31

Python 爬虫学习笔记之单线程爬虫

介绍 本篇文章主要介绍如何爬取麦子学院的课程信息(本爬虫仍是单线程爬虫),在开始介绍之前,先来看看结果示意图怎么样,是不是已经跃跃欲试了?首先让我们打开麦子学院的网址,然后找到麦子学院的全部课程信息,像下面这样这个时候进行翻页,观看网址的变
2022-06-04

scrapy 爬虫学习二[中间件的学习]

scrapy源码解析参考连接:https://www.jianshu.com/p/d492adf17312 ,直接看大佬的就行了,这里便就不多说了。今天要学习的是:Scrapy框架中的download middlerware【下载中间件】用
2023-01-31

学习爬虫的第一天

爬虫是什么?网络就如同蜘蛛网,而数据相当于里面的节点,爬虫如同蜘蛛,通过节点去获取蜘蛛网上的内容,获取想要的数据信息获取网页数据方式:1、浏览器访问——下载网页数据2、模拟浏览器对网页进行访问——解析数据——将所需要的内容保存在本地其中第二
2023-01-31

Python爬虫框架Scrapy 学习

开发环境PyCharm目标网站和上一次一样,可参考:http://dingbo.blog.51cto.com/8808323/1597695 但是这次不是在单个文件中运行,而是创建一个scrapy项目1.使用命令行工具创建scrapy项目的
2023-01-31

Python爬虫学习教程:天猫商品数据爬虫

天猫商品数据爬虫使用教程下载chrome浏览器查看chrome浏览器的版本号,下载对应版本号的chromedriver驱动pip安装下列包pip install seleniumpip install pyquery登录微博,并通过微博绑定
2023-06-02

python爬虫学习三:python正则

python爬虫学习三:python正则表达式自己写的一个爬虫:https://github.com/qester/wordpres_Crawler1、正则表达式基础a、正则表达式的大致匹配过程:1、依次拿出表达式和文本中的字符比较2、如果
2023-01-31

学习python爬虫能做什么

这篇文章主要介绍“学习python爬虫能做什么”,在日常操作中,相信很多人在学习python爬虫能做什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”学习python爬虫能做什么”的疑惑有所帮助!接下来,请跟
2023-06-27

学习爬虫必须学的基础知识

1.数据的来源1)用户自行产生2)去第三方的公司购买数据3)去免费的数据网站下载数据4)人工收集数据5)爬虫获取2.什么是爬虫网络爬虫(又被称为网页蜘蛛,网络机器人)就是模拟浏览器发送网络请求,接收请求响应,一种按照一定的规则,自动地抓取互
2023-06-02

【Python学习】爬虫报错处理bs4.

【BUG回顾】在学习Python爬虫时,运Pycharm中的文件出现了这样的报错:bs4.FeatureNotFound: Couldn’t find a tree builder with the features you request
2023-01-31

零基础怎么学习Python爬虫

本篇内容主要讲解“零基础怎么学习Python爬虫”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“零基础怎么学习Python爬虫”吧!  零基础如何学爬虫技术?对于迷茫的初学者来说,爬虫技术起步学习
2023-06-01

爬虫学习之第三章数据存储

什么是json:JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数
2023-01-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录