python爬虫库scrapy简单使用实例详解


Posted in Python onFebruary 10, 2020

最近因为项目需求,需要写个爬虫爬取一些题库。在这之前爬虫我都是用node或者php写的。一直听说python写爬虫有一手,便入手了python的爬虫框架scrapy.

下面简单的介绍一下scrapy的目录结构与使用:

首先我们得安装scrapy框架

pip install scrapy

接着使用scrapy命令创建一个爬虫项目:

scrapy startproject questions

相关文件简介:

scrapy.cfg: 项目的配置文件

questions/: 该项目的python模块。之后您将在此加入代码。

questions/items.py: 项目中的item文件.

questions/pipelines.py: 项目中的pipelines文件.

questions/settings.py: 项目的设置文件.

questions/spiders/: 放置spider代码的目录.

questions/spiders/xueersi.py: 实现爬虫的主体代码.

xueersi.py  爬虫主体

# -*- coding: utf-8 -*-
import scrapy
import time
import numpy
import re
from questions.items import QuestionsItem
class xueersiSpider(scrapy.Spider):
  name = "xueersi" # 爬虫名字
  allowed_domains = ["tiku.xueersi.com"] # 目标的域名
# 爬取的目标地址
  start_urls = [
    "http://tiku.xueersi.com/shiti/list_1_1_0_0_4_0_1",
    "http://tiku.xueersi.com/shiti/list_1_2_0_0_4_0_1",
    "http://tiku.xueersi.com/shiti/list_1_3_0_0_4_0_1",
  ]
  levels = ['偏易','中档','偏难']
  subjects = ['英语','语文','数学']

 # 爬虫开始的时候,自动调用该方法,如果该方法不存在会自动调用parse方法
  # def start_requests(self):
  #   yield scrapy.Request('http://tiku.xueersi.com/shiti/list_1_2_0_0_4_0_39',callback=self.getquestion)

# start_requests方法不存在时,parse方法自动被调用
  def parse(self, response):


 # xpath的选择器语法不多介绍,可以直接查看官方文档
    arr = response.xpath("//ul[@class='pagination']/li/a/text()").extract()
    total_page = arr[3]


 # 获取分页
    for index in range(int(total_page)):
      yield scrapy.Request(response.url.replace('_0_0_4_0_1',"_0_0_4_0_"+str(index)),callback=self.getquestion) # 发出新的请求,获取每个分页所有题目
  # 获取题目
  def getquestion(self,response):
    for res in response.xpath('//div[@class="main-wrap"]/ul[@class="items"]/li'):
      item = QuestionsItem() # 实例化Item类
      # 获取问题
      questions = res.xpath('./div[@class="content-area"]').re(r'<div class="content-area">?([\s\S]+?)<(table|\/td|div|br)')
      if len(questions):
        # 获取题目
        question = questions[0].strip()
        item['source'] = question
        dr = re.compile(r'<[^>]+>',re.S)
        question = dr.sub('',question)
        content = res.extract()
        item['content'] = question
        # 获取课目
        subject = re.findall(ur'http:\/\/tiku\.xueersi\.com\/shiti\/list_1_(\d+)',response.url)
        item['subject'] = self.subjects[int(subject[0])-1]
        # 获取难度等级
        levels = res.xpath('//div[@class="info"]').re(ur'难度:([\s\S]+?)<')
        item['level'] = self.levels.index(levels[0])+1
        
        # 获取选项
        options = re.findall(ur'[A-D][\..]([\s\S]+?)<(\/td|\/p|br)',content)
        item['options'] = options
        if len(options):
          url = res.xpath('./div[@class="info"]/a/@href').extract()[0]
          request = scrapy.Request(url,callback=self.getanswer)
          request.meta['item'] = item # 缓存item数据,传递给下一个请求
          yield request
      #for option in options:
  # 获取答案      
  def getanswer(self,response):
    
    res = response.xpath('//div[@class="part"]').re(ur'<td>([\s\S]+?)<\/td>')
    con = re.findall(ur'([\s\S]+?)<br>[\s\S]+?([A-D])',res[0]) # 获取含有解析的答案
    if con:
      answer = con[0][1]
      analysis = con[0][0] # 获取解析
    else:
      answer = res[0]
      analysis = ''
    if answer:
      item = response.meta['item'] # 获取item
      item['answer'] = answer.strip()
      item['analysis'] = analysis.strip()
      item['answer_url'] = response.url
      yield item # 返回item,输出管道(pipelines.py)会自动接收该数据

items.py 数据结构定义:

# -*- 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 QuestionsItem(scrapy.Item):
  content = scrapy.Field()
  subject = scrapy.Field()
  level = scrapy.Field()
  answer = scrapy.Field()
  options = scrapy.Field()
  analysis = scrapy.Field()
  source = scrapy.Field()
  answer_url = scrapy.Field()
  pass

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
import md5
class QuestionsPipeline(object):
  def __init__(self): 
    # 建立数据库连接 
    self.connect = pymysql.connect('localhost','root','','question',use_unicode=True,charset='utf8') 
    # 获取游标 
    self.cursor = self.connect.cursor() 
    print("connecting mysql success!") 
    self.answer = ['A','B','C','D']
  def process_item(self, item, spider):
    content = pymysql.escape_string(item['content'])

 # 获取题目hash值,使用该字段过滤重复的题目
    m1 = md5.new()  
    m1.update(content)
    hash = m1.hexdigest()
    selectstr = "select id from question where hash='%s'"%(hash)
    self.cursor.execute(selectstr)
    res = self.cursor.fetchone()
    # 过滤相同的题目
    if not res:



 # 插入题目
      sqlstr = "insert into question(content,source,subject,level,answer,analysis,hash,answer_url) VALUES('%s','%s','%s','%s','%s','%s','%s','%s')"%(content,pymysql.escape_string(item['source']),item['subject'],item['level'],item['answer'],pymysql.escape_string(item['analysis']),hash,item['answer_url'])
      self.cursor.execute(sqlstr)
      qid = self.cursor.lastrowid



 # 插入选项
      for index in range(len(item['options'])):
        option = item['options'][index]
        answer = self.answer.index(item['answer'])
        if answer==index:
          ans = '2'
        else:
          ans = '1'
        sqlstr = "insert into options(content,qid,answer) VALUES('%s','%s','%s')"%(pymysql.escape_string(option[0]),qid,ans)
        self.cursor.execute(sqlstr)
      self.connect.commit() 
      #self.connect.close() 
    return item

爬虫构建完毕后,在项目的根目录下运行

scrapy crawl xueersi # scrapy crawl 爬虫的名称

更多关于python爬虫库scrapy使用方法请查看下面的相关链接

Python 相关文章推荐
Python ldap实现登录实例代码
Sep 30 Python
Queue 实现生产者消费者模型(实例讲解)
Nov 13 Python
python+matplotlib实现动态绘制图片实例代码(交互式绘图)
Jan 20 Python
Python yield与实现方法代码分析
Feb 06 Python
Python产生Gnuplot绘图数据的方法
Nov 09 Python
Python中的 enum 模块源码详析
Jan 09 Python
python面向对象实现名片管理系统文件版
Apr 26 Python
pyqt5对用qt designer设计的窗体实现弹出子窗口的示例
Jun 19 Python
Win10用vscode打开anaconda环境中的python出错问题的解决
May 25 Python
Python发送邮件实现基础解析
Aug 14 Python
Python模拟键盘输入自动登录TGP
Nov 27 Python
python多线程爬取西刺代理的示例代码
Jan 30 Python
tensorflow 实现从checkpoint中获取graph信息
Feb 10 #Python
Python3 集合set入门基础
Feb 10 #Python
Django的CVB实例详解
Feb 10 #Python
TensorFlow实现checkpoint文件转换为pb文件
Feb 10 #Python
Django关于admin的使用技巧和知识点
Feb 10 #Python
Python实现括号匹配方法详解
Feb 10 #Python
Python re正则表达式元字符分组()用法分享
Feb 10 #Python
You might like
php获取数组长度的方法(有实例)
2013/10/27 PHP
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 2611816 bytes)
2014/11/08 PHP
PHP、Java des加密解密实例
2015/04/27 PHP
谈谈 PHP7新增功能
2015/12/16 PHP
PHP各种异常和错误的拦截方法及发生致命错误时进行报警
2016/01/19 PHP
PHP 实现 WebSocket 协议原理与应用详解
2020/04/22 PHP
区分JS中的undefined,null,&quot;&quot;,0和false
2007/03/08 Javascript
关于使用runtimeStyle属性问题讨论文章
2007/03/08 Javascript
抽出www.templatemonster.com的鼠标悬停加载大图模板的代码
2007/07/11 Javascript
js原生态函数中使用jQuery中的 $(this)无效的解决方法
2011/05/25 Javascript
jquery通过load获取文件的内容并跳到锚点的方法
2015/01/29 Javascript
jquery常用函数与方法汇总
2015/09/01 Javascript
jQuery语法小结(超实用)
2015/12/31 Javascript
js随机生成26个大小写字母
2016/02/12 Javascript
使用JS读取XML文件的方法
2016/11/25 Javascript
js实现页面刷新滚动条位置不变
2016/11/27 Javascript
Jquery Easyui表单组件Form使用详解(30)
2016/12/19 Javascript
深入解析ES6中的promise
2018/11/08 Javascript
JS实现查找数组中对象的属性值是否存在示例
2019/05/24 Javascript
Vue数字输入框组件示例代码详解
2020/01/15 Javascript
javascript 使用sleep函数的常见方法详解
2020/04/26 Javascript
vue 解决addRoutes多次添加路由重复的操作
2020/08/04 Javascript
wxPython框架类和面板类的使用实例
2014/09/28 Python
Python中模块pymysql查询结果后如何获取字段列表
2017/06/05 Python
Python 确定多项式拟合/回归的阶数实例
2018/12/29 Python
Python3打包exe代码2种方法实例解析
2020/02/17 Python
PyTorch加载自己的数据集实例详解
2020/03/18 Python
用python绘制樱花树
2020/10/09 Python
Python爬虫之Selenium库的使用方法
2021/01/03 Python
毕业生动漫设计求职信
2013/10/11 职场文书
办护照工作证明
2014/10/01 职场文书
师德师风个人整改措施
2014/10/27 职场文书
销售业务员岗位职责
2015/02/13 职场文书
2019最新婚庆对联集锦!
2019/07/10 职场文书
详解Redis在SpringBoot工程中的综合应用
2021/10/16 Redis
为了顺利买到演唱会的票用Python制作了自动抢票的脚本
2021/10/16 Python