爬取当当网python类书籍的信息(存储在mysql中)

我爬取到的数据是存储在mysql数据库中的,没有需要安装。

本文设计到的python库有:bs4、scrapy、pymysql、

首先在cmd命令行输入下图(1)的命令,显示下图(2)中的内容时,项目创建成功,然后用pycharm打开这个项目。

没有安装scrapy框架的建议用anaconda安装,然后在anacomda prompt输入(1)的命令

使用pycharm打开项目后目录结构如下(在spiders中新建mySpider.py、book下新建run.py):

然后分析当当网的图书数据进行分析,打开当当网,在搜索中输入python,看到如下页面:

此时的地址为:http://search.dangdang.com/?key=python&act=input

分析html代码的结构,我们看到每本书都是一个<li>的项目,而它们的结构是完全一样的,这些

<li>包含在一个<ul>中,我们只关心图书的名称title、作者author、出版时间date、出版社publisher、

价格price和内容简介detail。下面对提取这些信息的代码做一个分析:

1、title = li.xpath("./a[position()=1]/@title").extract_first()

<li>中有多个<a>标签,从html代码中可以看到书名信息包含在一个<a>的title属性中,因此通过position()=1

找出第一个<a>,然后取出title属性值就是书名title。

2、price = li.xpath("./p[@class='price']/span[@class='search_now_price']/text()").extract_first()

价格包含在<li>中的class='price'的<p>元素下面的class='search_now_price'的span元素的文本中

3、author = li.xpath("./p[@class='search_book_author']/span[position()=1]/a/@title").extract_first()

作者包含在<li>下面的class='search_book_author'的<p>元素下面的第一个<span>元素的<a>标签的

title属性中,其中span[position()=1]就是限定第一个<span>元素。

4、date = li.xpath("./p[@class='search_book_author']/span[position()=last()-1]/text()").extract_first()

出版日期包含在<li>下面的class='search_book_author'<p>元素下面的倒数第二个<span>元素的文本中

5、publisher = li.xpath("./p[@class='search_book_author']/span[position()=last()]/a/@title").extract_first()

出版社包含在<li>下面的class='search_book_author'的<p>元素下面的最后一个span元素的<a>标签中的title属性中。

6、detail = li.xpath("./p[@class='detail']/text()").extract_first()

在<li>下面的class='detail'的<p>的文本就是书的简介。

下面来看具体的代码:

1、编写items.py的数据项目类:

import scrapy
class BookItem(scrapy.Item):
    title = scrapy.Field()
    author = scrapy.Field()
    date = scrapy.Field()
    publisher = scrapy.Field()
    detail = scrapy.Field()
    price = scrapy.Field()

2、编写pipelines.py的数据处理类:

import pymysql

class BookPipeline(object):
    # 爬虫开始是执行的函数
    def open_spider(self, spider):
        print("opened")
        try:
            # 连接数据库,密码写自己的密码
            self.con = pymysql.connect(host="127.0.0.1",port=3306, user="root",passwd="123456", charset="utf8")
            self.cursor = self.con.cursor(pymysql.cursors.DictCursor)
            try:
                self.cursor.execute("create database mydb")
            except:
                pass
            self.con.select_db("mydb")
            try:
                self.cursor.execute("drop table books")
            except:
                pass
            try:
                sql = """
                        create table books(
                            bID varchar(8) primary key,
                            bTitle varchar(512),
                            bAuthor varchar(256),
                            bPublisher varchar(256),
                            bDate varchar(32),
                            bPrice varchar(16),
                            bDetail text
                        )ENGINE=InnoDB DEFAULT CHARSET=utf8;    # 保证建立的表与打开的数据库编码一致
                    """
                self.cursor.execute(sql)
            except:
                self.cursor.execute("delete from books")
            self.opened = True
            self.count = 0
        except Exception as err:
            print(err)
            self.opened = False

    def close_spider(self, spider):
        if self.opened:
            self.con.commit()
            self.con.close()
            self.opened = False
        print("closed")
        print("总共爬取", self.count, "本书籍")

    def process_item(self, item, spider):
        try:
            print(item["title"])
            print(item["author"])
            print(item["publisher"])
            print(item["date"])
            print(item["price"])
            print(item["detail"])
            print()
            if self.opened:
                self.count += 1     # 用来构造bID
                ID = str(self.count)
                while len(ID) < 8:
                    ID = "0" + ID
                # 插入数据到表中
                self.cursor.execute("insert into books(bID,bTitle,bAuthor,bPublisher,bDate,bPrice,bDetail) values(%s,%s,%s,%s,%s,%s,%s)",(ID, item["title"], item["author"], item["publisher"], item["date"], item["price"],item["detail"]))

        except Exception as err:
            print("wrong error:"+str(err))
        return item
  在scrapy的过程中一旦打开一个spider爬虫就会执行这个类的open_spider(self,spider)函数,一旦这个spider
关闭就执行这个类的close_spider(self,spider)函数,因此程序在open_spider函数中连接MySQL数据库,并创建操作
游标self.cursor,在close_spider中提交数据并关闭数据库,程序中使用count变量统计爬取的书籍数量
  在数据处理函数中每次有数据到达,就显示数据内容,并使用insert的SQL语句把数据插入到数据库中。

3、编写scrapy的配置文件setting.py的数据处理类:

找到以下两个地方,第一处打开,第二处修改

DEFAULT_REQUEST_HEADERS = {     #模拟浏览器
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
}
ITEM_PIPELINES = {
   'book.pipelines.BookPipeline': 300,
}

这样就可以把爬取的数据推送到pipelin的BookPipeline类中去了。

4、编写scrapy的爬虫程序mySpider.py:

import scrapy
from book.items import BookItem #如果你的目录结构和我不一样注意一下
from bs4 import UnicodeDammit
class MySpider(scrapy.Spider):
    name = "mySpider"
    key = 'python'
    source_url = 'http://search.dangdang.com/'
    def start_requests(self):   #程序开始时会调用
        url = MySpider.source_url+"?key="+MySpider.key+"&act=input"
        yield scrapy.Request(url=url, callback=self.parse)  # 调用parse函数
    def parse(self, response):
        try:
            dammit = UnicodeDammit(response.body, ["utf-8", "gbk"])
            data = dammit.unicode_markup
            selector = scrapy.Selector(text=data)
            lis = selector.xpath("//li['@ddt-pit'][starts-with(@class,'line')]")    # 取到当前页面中所有带有属性ddt-pit的<li>,即每一条书籍
            for li in lis:
                title = li.xpath("./a[position()=1]/@title").extract_first()
                price = li.xpath("./p[@class='price']/span[@class='search_now_price']/text()").extract_first()
                author = li.xpath("./p[@class='search_book_author']/span[position()=1]/a/@title").extract_first()
                date = li.xpath("./p[@class='search_book_author']/span[position()=last()-1]/text()").extract_first()
                publisher = li.xpath("./p[@class='search_book_author']/span[position()=last()]/a/@title").extract_first()
                detail = li.xpath("./p[@class='detail']/text()").extract_first()
                # detail 有时没有,结果为None
                item = BookItem()
                item["title"] = title.strip() if title else ""
                item["author"] = author.strip() if title else ""
                item["date"] = date.strip()[1:] if title else ""  #注意到日期前有一个符号/,所以从1开始取值
                item["publisher"] = publisher.strip() if publisher else ""
                item["price"] = price.strip() if price else ""
                item["detail"] = detail.strip() if detail else ""
                yield item  # 将爬取到的一条记录推送到pipelines.py由process_item函数处理
            #最后一页是link为None
            link = selector.xpath("//div[@class='paging']/ul[@name='Fy']/li[@class='next']/a/@href").extract_first()
            if link:
                url = response.urljoin(link)
                yield scrapy.Request(url=url, callback=self.parse)
        except Exception as err:
            print(err)

 仔细分析网站的HTML代码发现在一个<div class='paging'>的元素中包含了翻页的信息,<div>下面的<ul name='Fy'>下面的

<li class='next>下面的<a>链接就是下一页的链接,取出这个链接地址,通过response.urljoin函数整理成绝对地址,再次产生一个

scrapy.Request对象请求,回调函数仍为这个parse函数,这样就可以递归调用parser函数,实现下一个网页的数据爬取。

5、编写run.py:

from scrapy import cmdline
cmdline.execute("scrapy crawl mySpider -s LOG_ENABLED=False".split())

运行run.py,查看mysql数据库得到如下图所示结果:

 

  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值