爬虫入门之Scrapy框架实战(新浪百科豆瓣)(十二)

一 新浪新闻爬取

1 爬取新浪新闻(全站爬取)

项目搭建与开启

scrapy startproject sina
cd sina
scrapy genspider mysina http://roll.news.sina.com.cn/news/gnxw/gdxw1/index_2.shtml

2 项目setting配置

ROBOTSTXT_OBEY = False
ITEM_PIPELINES = {
   'sina.pipelines.SinaPipeline': 300,
}

3 启动文件start.py配置

import scrapy.cmdline
def main():
    # -o  ['json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle']
    scrapy.cmdline.execute(['scrapy','crawl','mysina'])
    
if __name__ == '__main__':
    main()

4 需求目标item配置

import scrapy

class SinaItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    newsTitle = scrapy.Field()
    newsUrl = scrapy.Field()
    newsTime = scrapy.Field()
    content = scrapy.Field()

5 爬虫逻辑文件配置mysina.py

import scrapy
import requests
from lxml import etree
from sina import items
from scrapy.spiders import CrawlSpider,Rule  #CrawlSpiders:定义了一些规则跟进link
from scrapy.linkextractors import LinkExtractor  #提取链接

class MysinaSpider(CrawlSpider): #继承了CrawlSpider因此parse需要重命名防止冲突
    name = 'mysina'
    allowed_domains = ['sina.com.cn']
    start_urls = ['http://roll.news.sina.com.cn/news/gnxw/gdxw1/index_2.shtml']
    '''
    Rule参数:link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=identity
    LinkExtractor部分参数: allow=(), deny=(), allow_domains=(), deny_domains=(), restrict_xpaths=()

    allow=(正则)允许的, deny=(正则)不允许的
    callback=回调函数
    follow= 跟随如果为True就跟随
    '''
    rules = [Rule(LinkExtractor(allow=('index_(\d+).shtml')),callback='getParse',follow=True)]

    def getParse(self, response): #重命名逻辑方法
        newsList = response.xpath("//ul[@class='list_009']/li")
        for news in newsList:

            item = items.SinaItem() #对其进行实例化
            newsTitle = news.xpath('./a/text()')[0].extract()
            newsUrl = news.xpath('./a/@href')[0].extract()
            newsTime = news.xpath('./span/text()')[0].extract()
            content = self.getContent(newsUrl)

            item['newsTitle'] = newsTitle
            item['newsUrl'] = newsUrl
            item['newsTime'] = newsTime
            item['content'] = content
            yield item

    def getContent(self,url):
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36"
        }
        response = requests.get(url,headers=headers).content.decode('utf-8','ignore')   #content二进制
        mytree = etree.HTML(response)
        contentList = mytree.xpath("//div[@class='article']//text()")
        print(contentList)
        content = ''
        for c in contentList:
            #Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
            content += c.strip().replace('\n','')  #保证content为整片文章
        return content

方法二 :mysina.py也可采用scrapy创建请求

# -*- coding: utf-8 -*-
import scrapy
import requests
from lxml import etree
from sina import items

from scrapy.spiders import CrawlSpider,Rule  #CrawlSpiders:定义了一些规则跟进link
from scrapy.linkextractors import LinkExtractor  #提取链接

class MysinaSpider(CrawlSpider):
    name = 'mysina'
    allowed_domains = ['sina.com.cn']
    start_urls = ['http://roll.news.sina.com.cn/news/gnxw/gdxw1/index_2.shtml']
    rules = [Rule(LinkExtractor(allow=('index_(\d+).shtml')),callback='getParse',follow=True)]

    def getParse(self, response):

        newsList = response.xpath("//ul[@class='list_009']/li")
        for news in newsList:

            newsTitle = news.xpath('./a/text()')[0].extract()
            newsUrl = news.xpath('./a/@href')[0].extract()
            newsTime = news.xpath('./span/text()')[0].extract()
    
            #构造请求(修改为框架Request构造请求)
            request = scrapy.Request(newsUrl,callback=self.getMataContent) #回调为getMataContent
            #使用meta传参
            request.meta['newsTitle'] = newsTitle
            request.meta['newsUrl'] = newsUrl
            request.meta['newsTime'] = newsTime
            yield request

    def getMataContent(self,response):
        '''
        getMataContent接受来自request请求后的响应response
        '''
        contentList = response.xpath("//div[@class='article']//text()")
        content = ''
        for c in contentList:
            content += c.extract().strip()
        item = items.SinaItem()
        #response响应数据对应字段赋值给item
        item['newsTitle'] = response.meta['newsTitle']
        item['newsUrl'] = response.meta['newsUrl']
        item['newsTime'] = response.meta['newsTime']
        item['content'] = content
        yield item

6 管道存储pipelines.py

import pymysql

class SinaPipeline(object):
    def __init__(self):
        self.conn = None
        self.cursor = None

    def open_spider(self,spider):
        self.conn = pymysql.connect(host='111.230.169.xxx',user='root',password='xxx',database='sina', port=3306,charset='utf8') #创建连接
        self.cursor = self.conn.cursor()  #创建数据库游标

    def process_item(self, item, spider):
        sql = 'insert into sina_news(newsTitle,newsUrl,newsTime,content) VALUES (%r,%r,%r,%r)'%(item['newsTitle'], item['newsUrl'], item['newsTime'], item['content'])
        self.cursor.execute(sql)  #执行sql语句
        self.conn.commit()  #提交
        return item

    def close_spider(self,spider):
        self.cursor.close() #关闭
        self.conn.close()

方法二 : pipelines.py 补充快速创建sql语句

import pymysql

class DemoPipeline(object):

    def __init__(self):
        self.conn = None
        self.cur = None

    def open_spider(self, spider):
        self.conn = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',
            password='123456',
            db='fate',
            charset='utf8')
        self.cur = self.conn.cursor()

    def process_item(self, item, spider):
        cols, values = zip(*item.items())  #zip打包返回两个参数
        sql = "INSERT INTO `%s` (%s) VALUES (%s)" % \
              (
                  'sina_news',
                  ','.join(cols),
                  ','.join(['%s'] * len(values))
               )
        self.cur.execute(sql, values) #执行sql语句并将values填充到%s
        self.conn.commit()
        return item

    def close_spider(self, spider):
        self.cur.close()
        self.conn.close()

二 百科资料的爬取

1 百科资料爬取

项目搭建与开启

scrapy startproject baike
cd baike
scrapy genspider mybaike baike.baidu.com/item/Python/407313

2 项目setting配置

ROBOTSTXT_OBEY = False
DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
}
ITEM_PIPELINES = {
   'baike.pipelines.BaikePipeline': 300,
}

3 启动文件start.py配置

import scrapy.cmdline
def main():
    # -o  ['json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle']
    scrapy.cmdline.execute(['scrapy','crawl','mybaike'])
    
if __name__ == '__main__':
    main()

4 需求目标items配置

import scrapy

class BaikeItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    level1Title = scrapy.Field()
    level2Title = scrapy.Field()
    content = scrapy.Field()

5 爬虫逻辑文件配置mybaike.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy.spiders import CrawlSpider,Rule
from scrapy.linkextractors import LinkExtractor
from baike.items import BaikeItem

class MybaikeSpider(CrawlSpider):
    name = 'mybaike'
    allowed_domains = ['baike.baidu.com']
    start_urls = ['https://baike.baidu.com/item/Python/407313']

    rules = [Rule(LinkExtractor(allow=('item/(.*)')),callback='getParse',follow=True)]

    def getParse(self, response):
        level1Title = response.xpath("//dd[@class='lemmaWgt-lemmaTitle-title']/h1/text()")[0].extract()
        level2Title = response.xpath("//dd[@class='lemmaWgt-lemmaTitle-title']/h2/text()")
        if len(level2Title) != 0:
            level2Title = level2Title[0].extract()
        else:
            level2Title = '待编辑'
        contentList = response.xpath("//div[@class='lemma-summary']//text()")
        content = ''
        for c in contentList:
            content += c.extract()
        item = BaikeItem()
        item['level1Title'] = level1Title
        item['level2Title'] = level2Title
        item['content'] = content
        yield item

6 管道存储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

class BaikePipeline(object):
    def __init__(self):
        self.conn = None
        self.cousor = None

    def open_spider(self, spider):
        # 连接
        self.conn = pymysql.connect(host='111.230.169.107', user='root', password="20111673",
                                    database='baike', port=3306,
                                    charset='utf8')
        # 游标
        self.cousor = self.conn.cursor()

    def process_item(self, item, spider):

        cols, values = zip(*item.items())

        # `表名`
        sql = "INSERT INTO `%s`(%s) VALUES (%s)" % \
              ('baike', ','.join(cols), ','.join(['%s'] * len(values)))

        self.cousor.execute(sql, values)
        self.conn.commit()

        return item

    def close_spider(self, spider):
        self.cousor.close()
        self.conn.close()

三 豆瓣电影的爬取

1 豆瓣电影排行版

项目搭建与开启

scrapy startproject douban
cd douban
scrapy genspider mysina movie.douban.com/top250

2 项目setting配置

ROBOTSTXT_OBEY = False
DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
   "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36"
}
ITEM_PIPELINES = {
   'douban.pipelines.DoubanPipeline': 300,
}

3 启动文件start.py配置

import scrapy.cmdline
def main():
    # -o  ['json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle']
    scrapy.cmdline.execute(['scrapy','crawl','mybaike'])
    
if __name__ == '__main__':
    main()

4 需求目标items配置

import scrapy

class DoubanItem(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field()
    movieInfo = scrapy.Field()
    star = scrapy.Field()
    quote = scrapy.Field()

5 爬虫逻辑文件配置mydouban.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import Request
from douban.items import DoubanItem

class MydoubanSpider(scrapy.Spider):
    name = 'mydouban'
    url = ['https://movie.douban.com/top250']
    start_urls = {'https://movie.douban.com/top250'} #方法1

    '''#方法二
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
    }

    def start_requests(self):
        url = 'https://movie.douban.com/top250'
        yield Request(url, headers=self.headers)
    '''

    def parse(self, response):
        item = DoubanItem()
        movies = response.xpath('//ol[@class="grid_view"]/li')

        for movie in movies:
            item['name'] = movie.xpath(".//div[@class='pic']/a/img/@alt").extract()[0]
            item['movieInfo'] = movie.xpath(".//div[@class='info']/div[@class='bd']/p/text()").extract()[0].strip()
            item['star'] = movie.xpath(".//div[@class='info']/div[@class='bd']/div[@class='star']/span[2]/text()").extract()[0]
            item['quote'] = movie.xpath('.//div[@class="star"]/span/text()').re(r'(\d+)人评价')[0]
            yield item

        next_url = response.xpath('//span[@class="next"]/a/@href').extract() #获取下一页链接
        if next_url:
            next_url = 'https://movie.douban.com/top250' + next_url[0]
            yield Request(next_url,callback=self.parse)  #执行回调

6 管道存储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

class DoubanPipeline(object):
    def __init__(self):
        self.conn = pymysql.connect(host='111.230.169.107', port=3306, user= 'root', passwd = 'xxx', database = 'douban',charset = 'utf8')
        self.cursor = self.conn.cursor()
        self.cursor.execute("truncate table Movie")   #此处设置每开启就清空
        self.conn.commit()

    def process_item(self, item, spider):
        try:
            self.cursor.execute("insert into Movie (name,movieInfo,star,quote) VALUES (%s,%s,%s,%s)",(item['name'], item['movieInfo'], item['star'], item['quote']))
            self.conn.commit()

        except pymysql.Error:
            print("Error%s,%s,%s,%s" % (item['name'], item['movieInfo'], item['star'], item['quote']))
        return item
    def close_spider(self, spider):
        self.cursor.close()
        self.conn.close()
posted @ 2018-07-08 16:12  诚实善良小郎君  阅读(394)  评论(0编辑  收藏  举报