scrapy爬虫项目的建立

前言

本文只涉及到scrapy爬虫项目的基础知识,不涉及网页信息的提取和反爬机制的处理等具体技术,由于本人对爬虫的学习比较浅显,有出错的地方欢迎指正.

一、什么是爬虫?

我相信能点进这份博客的人可能已经对爬虫有了大致了解,简单来说爬虫就是为了信息的获取,这些信息通常也能通过人工的方式获取,但是数据量一旦庞大起来,通过人工的方式就显得十分的不切实际,而爬虫程序可以为我们处理这些简单的重复无意义的操作.

通常而言,我们不会直接说我们在"爬数据",会比较高大上的说我们在做"数据规整"的工作.

关于爬虫的具体原理本人也不是特别清楚,我的理解是,通过爬虫程序向指定网站发送请求信息request,网站会给你一个回复报文response,熟悉web的同学应该知到,这个response中就包含了我们需要的信息,通常来说,这个response会被浏览器进行编译和执行,转换成我们熟悉的前端界面,我们需要的信息就包含在这个前端界面中,因此我们需要的信息也存在于这个response中.

简单来说,爬虫的工作是"伪装"成浏览器访问某一站点,再"伪装"成用户在这个站点中查询相关信息,最后拦截得到站点返回给浏览器的response,从中筛选得到我们需要的信息.

<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">

可能这一部分的讲解有点不太清楚,感兴趣的同学可以查阅其他资料

二、什么是scrapy

scrapy是python自带的一个爬虫框架,scrapy已经帮我们完成了许多工作,而我们只需要定制开发几个模块即可,这就使得开发一个爬虫程序变得十分简单.

三、新建一个scrapy项目

在新建一个项目之前,需要使用anaconda新建一个虚拟环境,然后下载需要使用的包,这里需要使用的包是scrapy.

在虚拟环境建立完成后,可以通过命令行的方式新建一个scrapy项目,主要分为三个步骤:

  1. 进入保存项目的文件目录
  2. 激活虚拟环境
  3. scrapy startproject name 来新建scrapy项目.
    在这里插入图片描述

上图中我省去了步骤1.

成功创建scrapy项目后,目录如下:

在这里插入图片描述

为了介绍更加方便,接下来我将以一个已经完成的完整的scrapy项目进行描述.一个完整的scrapy项目目录如下:
在这里插入图片描述

通过对比两张图可以看出,一个完整的scrapy项目只是多了几个py文件,大体结构并未改变.

四、各模块的作用

4.1 item.py

将需要爬取的信息封装成一个类,方便后期数据的保存,我的爬虫代码中需要保存房屋的价格,位置,楼层,社区,朝向,周围地铁等信息.

代码示例如下:

import scrapy
class QkhouseItem(scrapy.Item):
    price = scrapy.Field()
    location = scrapy.Field()
    floor = scrapy.Field()
    community = scrapy.Field()
    orientation = scrapy.Field()
    subway = scrapy.Field()
    pass

4.2 pipelines.py

pipelines.py是随着项目的创建而自动创建的,该模块主要是完成数据保存到外部文件中.在完整的代码中,一共有三个pipelines模块:pipelines.py将数据保存到txt文件中,pipelines_excel.py将数据保存到excel表格中,pipelines_mysql.py将数据保存到mysql数据库中.

pipelines.py代码如下:

class QkhousePipeline:
    def process_item(self, item, spider):
        global index
        with open("house.txt", "a", encoding='utf8') as fp:
            fp.write(item['price'] + "\t")
            fp.write(item['location'] + "\t")
            fp.write(item['floor'] + "\t")
            fp.write(item['community'] + "\t")
            fp.write(item['orientation'] + "\t")
            fp.write(item['subway']+ "\t")
            fp.write("\n")
        fp.close()
        return item

pipelines_excel.py代码如下:

from openpyxl import Workbook
index = 2
wb = Workbook()
sheet = wb.create_sheet("租房信息")
sheet.cell(row=1, column=1, value="位置")
sheet.cell(row=1, column=2, value="小区")
sheet.cell(row=1, column=3, value="价格")
sheet.cell(row=1, column=4, value="楼层")
sheet.cell(row=1, column=5, value="地铁")
sheet.cell(row=1, column=6, value="朝向")

class QkhousePipeline:
    def process_item(self, item, spider):
        global index

        """保存到excel中"""
        sheet.cell(row=index, column=1, value=item['location'])
        sheet.cell(row=index, column=2, value=item['community'])
        sheet.cell(row=index, column=3, value=item['price'])
        sheet.cell(row=index, column=4, value=item['floor'])
        sheet.cell(row=index, column=5, value=item['subway'])
        sheet.cell(row=index, column=6, value=item['orientation'])
        wb.save("house.xlsx")
        index += 1
        return item

pipelines_mysql.py代码如下:

import pymysql

pc = pymysql.connect(host='', user="", password="",
                     database="test", port=3306,
                     charset='UTF8MB4')
cs = pc.cursor()
sql = "show tables"
cs.execute(sql)
# print(cs.fetchall())
for i in cs.fetchall():
    if i[0] == 'qkhouse':
        print('表已经存在')
        break
else:
    sql = '''
           create table qkhouse(
           sno int primary key auto_increment,
           location varchar(100),
           community varchar(100),
           floor varchar(20),
           Orientation varchar(10),
           price varchar(200),
           subway varchar(100)
           )character set 'UTF8MB4'
           '''
    cs.execute(sql)

class QkhousePipeline:
    def process_item(self, item, spider):
        global pc, cs
        """保存到数据库中"""
        try:
            pc.ping(reconnect=True)
            with pc.cursor() as cs2:
                sql = "insert into qkhouse (location, community, floor, Orientation, price, subway) values (%s, " \
                      "%s, %s, %s, %s, %s) "
                cs2.execute(sql, [item['location'], item['community'], item['floor'], item['orientation'],
                                  item['price'], item['subway']])
                pc.commit()
        except Exception as e:
            print(e)
            pc.rollback()
        finally:
            pc.close()
        return item

你也可以将这些保存方式写在一个pipelines.py文件中,但是不方便代码的管理.

分成多个pipelines时,你需要修改setting.py中的代码,在65行附件有一段注释掉的代码:

#ITEM_PIPELINES = {
#    'qkhouse.pipelines.QkhousePipeline': 300,
#}

若你只有一个pipelines,直接取消注释即可,代码中的300表示优先级,因为只有一个pipelines,所以优先级设置的大小没有影响.

若有多个pipelines时,你就需要设置pipelines优先级的大小:

ITEM_PIPELINES = {
   'qkhouse.pipelines.QkhousePipeline': 1,
   'qkhouse.pipelines_excel.QkhousePipeline': 2,
   'qkhouse.pipelines_mysql.QkhousePipeline': 3,
}

4.3 qkhousespider.py

在刚创建的scrapy项目的spider目录下,只有一个init文件,我们需要在该目录下创建一个新的模块完成核心程序的编写.

import scrapy
from bs4 import BeautifulSoup
from ..items import QkhouseItem

class QkhouseSpider(scrapy.Spider):
    name = 'qkhousespider'
    allowed_domains = ['wh.qk365.com']
    start_urls = ['https://wh.qk365.com/list/p1']

    def parse(self, response):
        house_data = BeautifulSoup(response.body.decode('utf8'), 'html.parser')
        elem = house_data.find_all("div", {"class": "w1170 clearfix"})[0].ul.children
        index = 1
        for i in elem:
            if index % 2 == 1:
                index += 1
            else:
                url = i.a['href']
                index += 1
                yield scrapy.Request(url=url, callback=self.parse_detail)
        next = house_data.find_all("p", {"class": "easyPage"})[0]
        next_url = next.contents[len(next.contents)-2]['href']
        if next.contents[len(next.contents)-2]['onclick'] != "next.contents[len(next.contents)-2]['onclick']":
            yield scrapy.Request(url=next_url, callback=self.parse)
        print(next_url)
        pass

    def parse_detail(self, response):
        item = QkhouseItem()
        house_detail = \
            BeautifulSoup(response.body.decode('utf8'), 'html.parser').find_all("dl", {"class": "houSurvey clearfix"})[
                0].contents
        house_detail_lf = house_detail[1]
        house_detail_rg = house_detail[3]
        item['price'] = house_detail_lf.contents[1].text[5:12]
        item["orientation"] = house_detail_lf.contents[5].text[6:8]
        item['floor'] = house_detail_lf.contents[7].text[5:]
        item['community'] = house_detail_lf.contents[9].text[5:]
        item['subway'] = house_detail_rg.contents[3].text.replace(u'\xa0\r\n\t\t\t\t', u',').replace(u'\n', u',')[6:]
        item['location'] = house_detail_rg.contents[7].text.replace(u'\xa0\r\n\t\t\t\t', u',')[6:]
        yield item

因为涉及到爬取二级网页所以有parse和parse_detail两个函数,关于信息的提取我使用的是BeautifulSoup,关于数如何提取,建议看看其他大佬的博客,如果以后还有机会用到scrapy我也会补全这份内容(这部分知识丢的太久了,忘记了).

在parse_detail函数中,返回值用的是yield,这是python中的特有语法,你可以看成是每一次保存的item对象都"传输"到pipelines中进行保存.

4.4 settings.py

在配置文件中,我们之前提到过的pipelines需要对其进行修改外,还需要做其他的变动.
20行的代码改为:

ROBOTSTXT_OBEY = False

另外,很多网站具备反爬机制,也需要修改相应的配置文件.

4.5 其他文件

middlewares.py是项目自动生成的,目前我没有遇到过修改该文件的情形.
最后四个py文件,是算法可视化的模块,利用matplotlib来绘制表格图形,这是建立在将爬取的数据保存为外部文件的基础上进行的,算法可视化也不是必须的操作.

五、启动scrapy

scrapy的启动需要在终端输入命令:scrapy crawl name

scrapy crawl qkhousespider

我的程序中,在spider目录下面的qkhousespider.py文件中,可以看到==name==设置的值为qkhousespider.

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇