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实现排序算法
Feb 14 Python
5款非常棒的Python工具
Jan 05 Python
Python3.5基础之NumPy模块的使用图文与实例详解
Apr 24 Python
使用python画社交网络图实例代码
Jul 10 Python
python 魔法函数实例及解析
Sep 25 Python
python绘制雪景图
Dec 16 Python
Python计算信息熵实例
Jun 18 Python
python语言time库和datetime库基本使用详解
Dec 25 Python
五分钟学会怎么用python做一个简单的贪吃蛇
Jan 12 Python
10张动图学会python循环与递归问题
Feb 06 Python
如何在向量化NumPy数组上进行移动窗口
May 18 Python
Python语法学习之进程的创建与常用方法详解
Apr 08 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 移除数组重复元素的一点说明
2008/11/27 PHP
Yii2使用$this-&gt;context获取当前的Module、Controller(控制器)、Action等
2017/03/29 PHP
一个用js实现控制台控件的代码
2007/09/04 Javascript
推荐40款强大的 jQuery 导航插件和教程(上篇)
2012/09/14 Javascript
jquery延迟加载外部js实现代码
2013/01/11 Javascript
JS和JQUERY获取页面大小,滚动条位置,元素位置(示例代码)
2013/12/14 Javascript
jQuery unbind()方法实例详解
2016/01/19 Javascript
layui 对弹窗 form表单赋值的实现方法
2019/09/04 Javascript
vue中使用极验验证码的方法(附demo)
2019/12/04 Javascript
JS实现简单的表格增删
2020/01/16 Javascript
解决vue 使用setTimeout,离开当前路由setTimeout未销毁的问题
2020/07/21 Javascript
keep-alive保持组件状态的方法
2020/12/02 Javascript
Python安装第三方库的3种方法
2015/06/21 Python
关于numpy数组轴的使用详解
2019/12/05 Python
Flask中endpoint的理解(小结)
2019/12/11 Python
python使用docx模块读写docx文件的方法与docx模块常用方法详解
2020/02/17 Python
网页切图的CSS和布局经验与要点
2015/04/09 HTML / CSS
CSS3+Sprite实现僵尸行走动画特效源码
2016/01/27 HTML / CSS
微软瑞士官方网站:Microsoft瑞士
2018/04/20 全球购物
SQL Server的固定数据库角色都有哪些?对应的服务器权限有哪些?
2013/05/18 面试题
请解释一下webService? 如何用.net实现webService
2014/06/09 面试题
VLAN和VPN有什么区别?分别实现在OSI的第几层?
2014/12/23 面试题
介绍一下常见的木马种类
2014/11/15 面试题
金融专业个人求职信
2013/09/22 职场文书
教师师德教育的自我评价
2013/10/31 职场文书
网上签名寄语活动留言
2014/01/18 职场文书
秘书英文求职信范文
2014/01/31 职场文书
股权转让意向书
2014/04/01 职场文书
秋天的图画教学反思
2014/05/01 职场文书
2014乡镇干部纪律作风整顿思想汇报
2014/09/13 职场文书
高考升学宴答谢词
2015/01/20 职场文书
晚会开幕词
2015/01/28 职场文书
堂吉诃德读书笔记
2015/06/30 职场文书
领导离职感言
2015/08/03 职场文书
《跨越海峡的生命桥》教学反思
2016/02/18 职场文书
pytorch fine-tune 预训练的模型操作
2021/06/03 Python