这次最主要的问题就是,pipeline中的数据保存
全部代码见文末哦~
欢迎指正~
目标网站:http://jyzx.beibei.gov.cn/cqbbwz/002/002001/002001004/
1、先解析主网页,找到所有中标公示的url
2、再对应每个中标公示的url进行爬取
3、用正则进行提取
4、传输数据,通过字典键值对,从spider到pipeline,再保存下来
首先我尝试用urllib.request库进行爬取,结果什么都没爬到
于是学长让我抓包试试(然鹅我还并不会,fiddler还不怎么会用)
问了超级善良的小伙伴,他让我找这个aspx。没错,就是它。
所以,我就在这个页面中爬了呀
通过 .find_all(“a”),找到所有a标签,在找到其href属性
这样,我们就可以进入子网页了
首先,是报错Item does not support field: XXX
然后我找到自己代码中的这一块
于是我换了一个键值对试试
然后我发现它换了一个键错误,后来我想到,是我键值对的键,赋值的是中文,不是item里面的
去掉num_key这一行,再直接infoDict[“num_key”] = num_val,就没问题了
是我智障了
写入时是选择w而不是wb
于是我进行调试
这里的infoDict也没问题,不过name_key这里为空,一会还要改一下正则
然后我想到上面正确的列数和下面乱码的列数不一样,我想到自己在pipeline这里,有些键没有写,于是我把所有键都都写了 。
于是列数是一样的了,但是下面还是有这么多行乱码。
大胆猜测是pipeline写入的函数不对 。
我加上翻页后,发现爬不到
但是我尝试另外写一个用requests的函数,直接找链接,是可以的,于是猜测,是start_urls这里的问题,但是它又必须是列表类型
于是我换成这样就可以了
现在还有一个问题,就是有的网页是下载文件,我需要把这种情况去掉
调试了很久,终于尝试出,这样去除
有同学没有爬取表格,而是直接把网页截图下来,保存截图
我问他是怎么想到的,他说,看见右键后有个打印选项,于是他就试试,发现,其实是通过截图,转换成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()
感谢您的阅读!