scrapy实例(pipeline保存数据的各种错误)

scrapy实例一

——cqupthub 寒假任务二

这次最主要的问题就是,pipeline中的数据保存
全部代码见文末哦~
欢迎指正~

文章目录

    • scrapy实例一
    • ——cqupthub 寒假任务二
      • 任务说明
      • 爬取步骤
      • 解析主网页部分(parse函数)
      • 解析子网页 (parse_proj函数)
      • pipeline保存数据
          • ~~这里遇到的问题们~~
            • 问题一(item内容错误)
            • 问题二(文件写入的w or wb)
            • 问题三(写入后有乱码)
            • 问题四(start_urls的类型)
            • 问题五(去掉附件形式)
      • 瞎扯扯
      • 最后附上代码吧

任务说明

scrapy实例(pipeline保存数据的各种错误)_第1张图片
目标网站:http://jyzx.beibei.gov.cn/cqbbwz/002/002001/002001004/

爬取内容:
scrapy实例(pipeline保存数据的各种错误)_第2张图片
框完才发现自己基本都框上了,嘻嘻嘻。

爬取步骤

1、先解析主网页,找到所有中标公示的url
2、再对应每个中标公示的url进行爬取
3、用正则进行提取
4、传输数据,通过字典键值对,从spider到pipeline,再保存下来

解析主网页部分(parse函数)

首先我尝试用urllib.request库进行爬取,结果什么都没爬到

于是学长让我抓包试试(然鹅我还并不会,fiddler还不怎么会用)
问了超级善良的小伙伴,他让我找这个aspx。没错,就是它。
scrapy实例(pipeline保存数据的各种错误)_第3张图片
所以,我就在这个页面中爬了呀
scrapy实例(pipeline保存数据的各种错误)_第4张图片

通过 .find_all(“a”),找到所有a标签,在找到其href属性
这样,我们就可以进入子网页了

解析子网页 (parse_proj函数)

  1. 北碚县区的项目,有的是表格形式,有的是图片形式
    所以我们先判断子网页是什么形式
    这里,我通过判断是否有某个标签,来判断是下载图片,还是爬表格
  2. 下载图片的话,就要找到图片的链接,然后下到本地
  3. 如果是附件的话,就提取附件链接
  4. 爬表格就是各种正则了

pipeline保存数据

这里遇到的问题们
  1. 在保存为csv格式这里,卡了很久,不知道怎么操作
问题一(item内容错误)

首先,是报错Item does not support field: XXX
scrapy实例(pipeline保存数据的各种错误)_第5张图片
然后我找到自己代码中的这一块
scrapy实例(pipeline保存数据的各种错误)_第6张图片

于是我换了一个键值对试试
然后我发现它换了一个键错误,后来我想到,是我键值对的键,赋值的是中文,不是item里面的
去掉num_key这一行,再直接infoDict[“num_key”] = num_val,就没问题了
是我智障了

问题二(文件写入的w or wb)

写入时是选择w而不是wb

问题三(写入后有乱码)

scrapy实例(pipeline保存数据的各种错误)_第7张图片
于是我进行调试
scrapy实例(pipeline保存数据的各种错误)_第8张图片
这里的infoDict也没问题,不过name_key这里为空,一会还要改一下正则

然后我想到上面正确的列数和下面乱码的列数不一样,我想到自己在pipeline这里,有些键没有写,于是我把所有键都都写了
于是列数是一样的了,但是下面还是有这么多行乱码。
大胆猜测是pipeline写入的函数不对

scrapy实例(pipeline保存数据的各种错误)_第9张图片
于是,我注释掉这一句就没问题了

问题四(start_urls的类型)

我加上翻页后,发现爬不到
在这里插入图片描述
但是我尝试另外写一个用requests的函数,直接找链接,是可以的,于是猜测,是start_urls这里的问题,但是它又必须是列表类型
scrapy实例(pipeline保存数据的各种错误)_第10张图片
于是我换成这样就可以了
scrapy实例(pipeline保存数据的各种错误)_第11张图片

问题五(去掉附件形式)

现在还有一个问题,就是有的网页是下载文件,我需要把这种情况去掉
scrapy实例(pipeline保存数据的各种错误)_第12张图片
调试了很久,终于尝试出,这样去除
scrapy实例(pipeline保存数据的各种错误)_第13张图片

瞎扯扯

有同学没有爬取表格,而是直接把网页截图下来,保存截图
我问他是怎么想到的,他说,看见右键后有个打印选项,于是他就试试,发现,其实是通过截图,转换成pdf,然后打印
于是,他就通过selenium来截图
绝对是一波sao操作 啊!

最后附上代码吧

spider 部分

import scrapy
import re
from bs4 import BeautifulSoup
import urllib
from county_gov.items import CountyGovItem
import pdb


class BeibeiSpider(scrapy.Spider):
    name = 'beibei'

    # 这里是翻页
    start_urls = []
    for i in range(1, 43):
        start_urls.append('http://jyzx.beibei.gov.cn/cqbbwz/showmain/zbgsmore.aspx?Paging=' + str(i))

    # 解析主页面的函数
        def parse(self, response):
            contents = response.body
            contents = contents.decode("utf-8")
            # pdb.set_trace()  # 没问题
            soup = BeautifulSoup(contents, "lxml")

            for i in soup.find_all("a"):
                try:
                    url_left = i["href"]
                    url = "http://jyzx.beibei.gov.cn" + str(url_left)
                    yield scrapy.Request(url, callback=self.parse_proj)
                except:
                    continue

    # 解析子网页的函数
        def parse_proj (self, response):
            soup = BeautifulSoup(response.text)

            # pdb.set_trace()   # 没问题

            # 判断是否为图片形式
            # 有图片,爬图片的链接,下载下来
            if len(soup.find_all(name="img", attrs={"border": "0"})):
                for i in soup.find_all(name="img", attrs={"border": "0"}):
                    # print(i)
                    url_l = i["src"]  # 剩余部分的url
                url = "http://jyzx.beibei.gov.cn" + str(url_l)
                urllib.request.urlretrieve(url, '{}.jpg'.format(str(url[-10:-1])))    # 这里的名称要改!!!!!

            # 没有图片,为任务一的表格形式
            elif len(soup.find_all("tbody")):
                contents = soup.find('tbody')
                text = ""

                for i in contents.find_all('span'):
                    i = str(i)
                    ii = re.findall(">(.*)<", i)
                    for a in ii:
                        text += str(a)  # 全部的内容出来了

                # pdb.set_trace()

                newtext1 = text.replace(" ", "")
                newtext2 = newtext1.replace("\r", "")
                newtext3 = newtext2.replace("\n", '')
                newtext4 = newtext3.replace("\t", "")
                newtext5 = newtext4.replace("\xa0", "")
                newtext6 = newtext5.replace("", "")
                newtext7 = newtext6.replace("", "")
                newtext8 = newtext7.replace("", "")
                newtext9 = newtext8.replace("", "")
                newtext10 = newtext9.replace("", "")
                newtext11 = newtext10.replace("", "")
                text = newtext11.replace("None", "")

                # pdb.set_trace()

                # 这里用一个字典来装对应信息
                # infoDict = {}
                infoDict = CountyGovItem()

                # 各种正则(可能还要改)

                # 项目编码
                # num_key = "num_key"
                num_val = ""
                try:
                    num = re.findall(r'项目编码:(.*)项目名称', text)
                    for i in num:
                        num_val = i
                except:
                    num_val = "--"
                infoDict['num'] = num_val

                # 项目名称
                # name_key = "项目名称"
                name_val = ""
                try:
                    name = re.findall(r'项目名称:(.*)工程监理招标人|项目名称:(.*)工程招标人|项目名称:(.*)招标人', text)
                    ls = []  # 是 {()}, 里面是个大元组,这里把元组变成列表
                    for i in name:
                        ls.append(''.join(list(i)))
                    for i in ls:
                        name_val = i
                except:
                    name_val = "--"
                infoDict['name'] = name_val

                # 工程监理招标人
                # spy_key = "工程监理招标人"
                spy_val = ""
                try:
                    spy = re.findall(r'招标人:(.*)联系电话', text)
                    for i in spy:
                        if "联系电话" in i:
                            char = "联系电话"
                            site = i.find(char)  # 这里找到第一个的地方
                            # print(site)
                            spy_val = i[0:site]
                except:
                    spy_val = "--"
                infoDict['spy'] = spy_val

                # 招标代理机构
                # agency_key = "招标代理机构"
                agency_val = ""
                try:
                    agency = re.findall(r'招标代理机构:(.*)公司', text)
                    for i in agency:
                        if "公司" in i:
                            char = "公司"
                            site = i.find(char)  # 这里找到第一个的地方
                            # print(site)
                            agency = i[0:site]
                            agency = agency.replace(',', "")
                            agency_val = agency + "公司"
                        if "/" in agency_val:
                            agency_val = "--"
                except:
                    agency_val = "--"
                infoDict['agency'] = agency_val

                # 第一中标候选人
                # per1_key = "第一中标候选人"
                per1_val = ""
                try:
                    per1 = re.findall(r'第一中标候选人:(.*)第二', text)
                    for i in per1:
                        per1_val = i
                except:
                    per1_val = "--"
                infoDict['per1'] = per1_val

                # 第二中标候选人
                # per2_key = "第二中标候选人"
                per2_val = ""
                try:
                    per2 = re.findall(r'第二中标候选人:(.*)第三', text)
                    for i in per2:
                        per2_val = i
                except:
                    per2_val = "--"
                infoDict['per2'] = per2_val

                # 第三中标候选人
                # per3_key = "第三中标候选人"
                per3_val = ""
                try:
                    per3 = re.findall(r'第三中标候选人:(.*)公司', text)
                    for i in per3:
                        if "公司" in i:
                            char = "公司"
                            site = i.find(char)  # 这里找到第一个的地方
                            # print(site)
                            per3 = i[0:site]
                            per3 = per3.replace(',', "")
                            per3_val = per3 + "公司"
                except:
                    per3_val = "--"
                infoDict['per3'] = per3_val

                # 中标人
                # per_key = "中标人"
                per_val = ""
                try:
                    per = re.findall(r'中标人:(.*)公司', text)
                    for i in per:
                        per_val = i + "公司"
                except:
                    per_val = "--"
                infoDict['per'] = per_val

                # 中标价
                # price_key = "中标价"
                price_val = ""
                try:
                    per = re.findall(r'中标价:(.*)元', text)
                    for i in per:
                        price_val = i + "元"
                except:
                    price_val = "--"
                infoDict['price'] = price_val

                # 投诉受理部门
                # complain_key = "投诉受理部门"
                complain_val = ""
                try:
                    complain = re.findall(r'投(.*)诉受理部门:(.*)备注', text)
                    # print(complain)
                    ls = []  # 是 {()}, 里面是个大元组,这里把元组变成列表
                    for i in complain:
                        ls.append(''.join(list(i)))

                    for i in ls:
                        # 可能不止一个受理部门,先分开
                        if "联系电话" in i:
                            ls_complain = i.split("联系电话")

                            # 去掉电话,再连一起
                            complaints = ""
                            for a in ls_complain:
                                if "023" in a:
                                    a = a.replace(":", "")
                                    a = a.replace("-", "")
                                    for num in range(10):
                                        a = a.replace(str(num), "")
                                complaints += a + " "

                    complain_val = complaints

                except:
                    complain_val = "--"
                infoDict['complain'] = complain_val

                # 日期
                # date_key = "日期"
                try:
                    date_val = re.findall(r'(201\d/\d{1,2}/\d{1,2}|201\d年\d{1,2}月\d{1,2}日|201\d-\d{1,2}-\d{1,2})', text)
                    date_val = date_val[0]
                except:
                    date_val = "——"
                infoDict['date'] = date_val


                # pdb.set_trace()

                yield infoDict

            # 排除文件的情况
            else:
                pass

pipeline部分

# -*- 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 csv
import os
import pdb
from county_gov.items import CountyGovItem


class CountyGovPipeline(object):

    def __init__(self):
        self.f = open('gov.csv', "w")

        self.writer = csv.writer(self.f)

    def process_item(self, item, spider):
        if (item['name']):
        # pdb.set_trace()
        # self.writer.writerow((item['name'], item['num'], item['date'], item['spy'], item['agency'], item['per1'], item['per2'], item['per3'], item['per'], item['price'], item['complain']))
            return item
        else:
            pass

    def close_spider(self, spider, item):
        self.f.close()

感谢您的阅读!

你可能感兴趣的:(python)