python scrapy爬虫

一、爬虫基础知识

1.网络爬虫的主要类型

  • 通用爬虫:从一些URL 扩充到整个WEB,主要为搜索引擎、大型WEB服务商采集数据;
  • 聚焦爬虫:主要爬取特定主题的内容;
  • 增量式爬虫:对已下载网页进行更新,只爬取页面更新的内容;
  • 深层页面爬虫:指需要用户提交一些关键字才能获得的页面。

2.网页解析工具

  • 正则表达式
  • LXML库
  • BS

3.python爬虫框架

  • Scrapy
  • Pyspider
  • Cola

4.HTTP请求信息

请求头、请求方法、请求正文三部分组成

  1. 请求方法:POST/GET/DELETE/PUT/OPTIONS/TRACE/HEAD
  2. 请求头:一般反爬虫机制通过读取请求头来判断

二、Requests

1.基本属性

url:
params: (optional)
kwargs:

  • data: (optional)
  • json: (optional)
  • headers: (optional)
  • cookies: (optional)
  • files: (optional) 上传文件
  • auth: (optional)
  • timeout: (optional) 超时等待时间
  • allow_redirects: (optional) Boolean 开启、禁用重定向
  • proxies: (optional) 设置代理
  • verify: (optional)
  • stream: (optional)
  • cert: (optional) 支持的证书种类是pem,可用此参数转换证书
import requests
url = 'https://www.douban.com/search'
param = {
        'q':'python',
        'cat':1001,
    }
res = requests.get(url=url,params=param)
#自动将param组成网址
#https://www.douban.com/search?q=python&cat=1001
res1 = requests.get(url=url,timeout=1)#自动设置timeout秒
print(res.text) #转码后的
print(res.content) #unicode 使用.decode('utf-8')解码
print(res.headers) #头部信息
print(res.url)
print(res.encoding) #网页编码方式
res1.history #Request对象的列表(如果出现301就是发生了重定向)
print(res.status_code) #200
print(res.reason) #OK
print(res.raw) #原始响应内容,返回一个requests对象

2、保持会话、代理

requests.session()

小工具

1.网址拼接工具

from urllib.parse import urlparse#网址拆分
from urllib.parse import urlunparse#网址拼接
urlparse("https://www.douban.com/search?cat=1001&q=python")
>>ParseResult(scheme='https', netloc='www.douban.com', path='/search', params='', query='cat=1001&q=python', fragment='')
urlunparse(['https','www.douban.com','search','',"q=python",''])
>>'https://www.douban.com/search?q=python'

2.lxml库解析网页

import requests
from lxml import etree
url = 'http://www.newsmth.net/nForum/#!article/HouseRent/552610'
data = requests.get(url=url)
selector = etree.HTML(data.text)
selector.xpath('//title/text()')
>>['水木社区-源于清华的高知社群']

3.xpath语法

语法作用
/从根节点选取。
//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
.选取当前节点。
选取当前节点的父节点。
@选取属性。
bookstore选取 bookstore 元素的所有子节点。
/bookstore选取根元素 bookstore。
bookstore/book选取属于 bookstore 的子元素的所有 book 元素,不包含孙节点。
//book选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang选取名为lang的所有属性。
/bookstore/book[1]选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last( )]选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last( )-1]选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position( ) < 3]选取最前面的两个属于 bookstore 元素的子元素的 book 元素
//title[@lang]选取所有拥有名为 lang 的属性的 title 元素
//title[@lang=‘eng’]选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35]选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35
/bookstore/book[price>35]/title选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35
*匹配任何元素节点。
@*匹配任何属性节点。
node()匹配任何类型的节点。
//book/title l//book/price选取 book 元素的所有 title 和 price 元素。
//title l //price选取文档中的所有 title 和 price 元素。
/bookstore/book/title l //price选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。

4.Beautiful Soup语法

from bs4 import BeautifulSopu

5.正则表达式

import re
re语法作用
^以……开头
$以……结尾
.任意一个字符
*出现0–N次
( )提取子串
?放在子串前匹配字符(非贪婪模式)
“booobby”".*(b.*b). * "-----> ‘bb’ 贪婪模式,倒序匹配
“booobby”".*?(b.*b). * "-----> ‘booobb’
“booobby”".?(b.?b). * "-----> ‘booob’
+出现1–N次
{m},{m,n},{m,}出现m次,出现m–n次,出现m次以上
[0-9],[ ^ 1 ] ,[135]0–9,非1数字,1或3或5
[.],[*]匹配. ,匹配* ,不再表示一个或多个字符
[a-z],[A-Z],[A-Z0-9]a到z,A到Z,A到Z 或0到9
/s任意空白字符串 [\t\n\r\f]
/S一个非空格就行
/wa到z 或 A到Z 或0到9 或下划线
/W非(a到z 或 A到Z 或0到9),一些特殊符号
/d一个0到9
/D非一个0到9
[/u4E00-/u9FA5]大多数汉字

参考书

1.齐文光,《python网络爬虫实例教程》,人民邮电出版社:2018.08

三、Scrapy

1.Scrapy 各命令

  bench         Run quick benchmark test
  #测试是否安装成功及每分钟发送多少个包
  
  fetch         Fetch a URL using the Scrapy downloader
  #使用爬虫下载一个网页
  #scrapy fetch "http://www.baidu.com"
  
  genspider     Generate new spider using pre-defined templates
  #创建一个爬虫
  
  runspider     Run a self-contained spider (without creating a project)
  #启动一个爬虫,无需创建整体项目
  
  settings      Get settings values
  
  shell         Interactive scraping console
  #类似Ipython 环境,使用scrapy shell "http://www.baidu.com" ,直接返回response变量,主要来测试xpath是否正确
  
  startproject  Create new project
  scrapy startproject <project_name> [project_dir]
  #创建一个爬虫项目
  
  version       Print Scrapy version
  #打印版本号
  
  view          Open URL in browser, as seen by Scrapy
  #用浏览器的视图来查看页面
  
  crawl         Run a spider
  #运行一个爬虫,必须在爬虫所在的目录中才能运行

2.Scrapy使用

1)创建爬虫项目
scrapy startproject Itcast 

ITcast
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-36.pyc
│   │   ├── items.cpython-36.pyc
│   │   ├── pipelines.cpython-36.pyc
│   │   └── settings.cpython-36.pyc
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders
│       ├── __init__.py
│       ├── __pycache__
│       │   ├── __init__.cpython-36.pyc
│       │   └── itcast.cpython-36.pyc
│       └── **itcast.py** 
2)在ITcast项目下的一个爬虫itcast(在spiders文件下)
scrapy genspider itcast "www.itcast.cn"
3)执行itcast这个爬虫(在spiders文件下)
scrapy crawl itcast

4)itcast.py写法
不使用管道,直接把结果写入文件或直接打印出来
'''
以下内容是itcast.py文件中的
'''
import scrapy
from Demo.items import DemoItem #引入自定义的items

class ItcastSpider(scrapy.Spider):  #继承Spider类
    name = 'itcast' #genspider产生的
    allowed_domains = ['http://www.itcast.cn']  #过滤作用,可删掉
    start_urls = ['http://www.itcast.cn/channel/teacher.shtml']

    def parse(self, response):
        items = [] #可使用这种定义一个列表,最后把文件存储到单独文件里
        datas = response.xpath("//div[@class='li_txt']")
        for data in datas:
            t_name = data.xpath("./h3/text()").extract()
            t_title = data.xpath("./h4/text()").extract()
            t_info = data.xpath("./p/text()").extract()
            print(t_name)
            item = DemoItem() #结构类似字典
            item["t_name"] = t_name[0]
            item["t_title"] = t_title[0]
            item["t_info"] = t_info[0]
            items.append(item)
        print(items)
用管道来处理
把结果写到json文件中
'''
以下内容是itcast.py文件中的
'''
class ItcastSpider(scrapy.Spider):
    name = 'itcast'
    allowed_domains = ['http://www.itcast.cn']
    start_urls = ['http://www.itcast.cn/channel/teacher.shtml']

    def parse(self, response):
        datas = response.xpath("//div[@class='li_txt']")
        for data in datas:
            t_name = data.xpath("./h3/text()").extract()
            t_title = data.xpath("./h4/text()").extract()
            t_info = data.xpath("./p/text()").extract()
            print(t_name)
            item = DemoItem()
            item["t_name"] = t_name[0]
            item["t_title"] = t_title[0]
            item["t_info"] = t_info[0]
            yield item   #返回item,直接会由pipelines.py来处理
'''
以下内容是pipelines.py文件中的
需要打开setting中的 ITEM_PIPELINES 
'''
import json

class DemoPipeline(object):
    def __init__(self): #初始化时候打开文件
        self.f = open('itcastTeacher.json','wb')

    def process_item(self, item, spider): #item对应上面yield返回的item
        content = json.dumps(dict(item),ensure_ascii=False) + ", \n"
        self.f.write(content.encode('utf-8')) #encode将str转成byte,所以打开的时候用'wb'
        return item #告诉调度器这条item处理完成,因此return不可少

    def close_spider(self,spider):#结束爬虫的时候关闭文件
        self.f.close()

把结果写到数据库中
注意事项

1.scrapy是多线程
在这里插入图片描述
2.只爬取了一条数据原因
一般由于xpath取的有问题

3.只爬取了第一页原因

 DEBUG: Filtered offsite request to 'www.kuaidaili.com': <GET https://www.kuaidaili.com/free/inha/2/>
 #由于在allow_domain中将第二页网址过滤掉了,因此有两种解决方案:
1. 在 allowed_domains 中加入 url 或将www前面的都删掉;
2. 在 scrapy.Request() 函数中将参数 dont_filter=True 设置为 True。

参照:Scrapy之Request函数回调未执行解决方案
4.json读取dumps存放的数据报异常
由于json读完数据将转换成字典,而字母key是唯一的,因此会报:json.decoder.JSONDecodeError: Extra data:
加粗样式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值