Django+Scrapy完成微博首页热点的提取和网页显示
目錄
1. 本系統編寫的思路
2.?系統的目錄結構
3.?項目建立和編程代碼過程展示
4.?效果展示
5.?碰到的問題及解決思路(重要)
6.?總結
1. 本系統編寫的思路
系統是采用的Django+Scrapy+Mysql三層架構進行開發的,主要思路是我們通過scrapy框架進行微博熱點的爬取,經過一系列的處理最終成為我們想要的item,然后存入mysql數據庫,最后Django從數據庫中讀取數據在網頁上輸出。其中我們在django和scrapy兩個框架之間使用了scrapy-djangoitem工具包,將從scrapy得到的item與django的model建立關聯,通過django強大的orm管理,直接將item存入數據庫,減少了在scrapy編寫sql的過程,提高了效率。除此之外,本系統開發十分簡單,特別適合剛入門的童鞋學習。
2.?系統的目錄結構
目錄的結構影響到django和scrapy框架間是否能夠通過scrapy-djangoitem進行連接,由于我之前在這之間碰到了很大的彎路,所以我這里選擇了一種比較簡答的項目創建方式,可以在之后的環境變量中省卻很大的功夫(我還沒從坑中完全爬起),更好的連接django和scrapy。
│ ?manage.py
│ ?tree.txt
│ ?
├─.idea
│ ?│ ?DjangoRelateScrapy.iml
│ ?│ ?misc.xml
│ ?│ ?modules.xml
│ ?│ ?workspace.xml
│ ?│ ?
│ ?├─inspectionProfiles
│ ?└─libraries
│ ? ? ? ? ?R_User_Library.xml
│ ? ? ? ? ?
├─DjangoRelateScrapy
│ ?│ ?settings.py
│ ?│ ?urls.py
│ ?│ ?wsgi.py
│ ?│ ?__init__.py
│ ?│ ?
│ ?└─__pycache__
│ ? ? ? ? ?settings.cpython-37.pyc
│ ? ? ? ? ?urls.cpython-37.pyc
│ ? ? ? ? ?wsgi.cpython-37.pyc
│ ? ? ? ? ?__init__.cpython-37.pyc
│ ? ? ? ? ?
├─microblog
│ ?│ ?admin.py
│ ?│ ?apps.py
│ ?│ ?models.py
│ ?│ ?tests.py
│ ?│ ?urls.py
│ ?│ ?views.py
│ ?│ ?__init__.py
│ ?│ ?
│ ?├─migrations
│ ?│ ?│ ?0001_initial.py
│ ?│ ?│ ?0002_auto_20190502_2117.py
│ ?│ ?│ ?__init__.py
│ ?│ ?│ ?
│ ?│ ?└─__pycache__
│ ?│ ? ? ? ? ?0001_initial.cpython-37.pyc
│ ?│ ? ? ? ? ?0002_auto_20190502_2117.cpython-37.pyc
│ ?│ ? ? ? ? ?__init__.cpython-37.pyc
│ ?│ ? ? ? ? ?
│ ?└─__pycache__
│ ? ? ? ? ?admin.cpython-37.pyc
│ ? ? ? ? ?models.cpython-37.pyc
│ ? ? ? ? ?urls.cpython-37.pyc
│ ? ? ? ? ?views.cpython-37.pyc
│ ? ? ? ? ?__init__.cpython-37.pyc
│ ? ? ? ? ?
├─static
│ ?├─css
│ ?│ ? ? ?a.css
│ ?│ ? ? ?
│ ?├─img
│ ?│ ? ? ?approve.png
│ ?│ ? ? ?comment.png
│ ?│ ? ? ?jiji.png
│ ?│ ? ? ?repost.png
│ ?│ ? ? ?weibo.png
│ ?│ ? ? ?
│ ?└─js
├─templates
│ ? ? ?test.html
│ ? ? ?weibo.html
│ ? ? ?
└─weibo
? ? │ ?scrapy.cfg
? ? │ ?
? ? └─weibo
? ? ? ? │ ?items.py
? ? ? ? │ ?main.py
? ? ? ? │ ?middlewares.py
? ? ? ? │ ?pipelines.py
? ? ? ? │ ?settings.py
? ? ? ? │ ?__init__.py
? ? ? ? │ ?
? ? ? ? ├─spiders
? ? ? ? │ ?│ ?WBlog.py
? ? ? ? │ ?│ ?__init__.py
? ? ? ? │ ?│ ?
? ? ? ? │ ?└─__pycache__
? ? ? ? │ ? ? ? ? ?WBlog.cpython-37.pyc
? ? ? ? │ ? ? ? ? ?__init__.cpython-37.pyc
? ? ? ? │ ? ? ? ? ?
? ? ? ? └─__pycache__
? ? ? ? ? ? ? ? items.cpython-37.pyc
? ? ? ? ? ? ? ? main.cpython-37.pyc
? ? ? ? ? ? ? ? pipelines.cpython-37.pyc
? ? ? ? ? ? ? ? settings.cpython-37.pyc
? ? ? ? ? ? ? ? __init__.cpython-37.pyc
或者:
? ? ? ? ? ? ? ??
3.?項目建立和編程代碼過程展示
1. 首先我們新建一個Django項目
django-admin startproject DjangoRelateScrapy2.?打開新建的django項目,然后新建一個app
cd DjangoRelateScrapy python manage.py startapp microblog3.?在django的根目錄下,即DjangoRelateScrapy項目目錄下,創建scrapy項目
scrapy startproject weibo4.?進入創建的scrapy項目,生成spider類
cd weibo scrapy genspider WBlog "weibo.com"5.?以上我們基本的項目的結構就創建完畢,接下來讓我們從scrapy項目開始,一步步編寫代碼和配置文件,編寫核心的爬蟲文件WBlog.py:
import json import reimport scrapy from scrapy.spiders import CrawlSpiderfrom weibo.items import WeiboItemclass WblogSpider(CrawlSpider):name = 'WBlog'aallowed_domains = ['weibo.com']offset = 0base_url = "https://weibo.com/a/aj/transform/loadingmoreunlogin?ajwvr=6&category=1760&page={0}&lefnav=0&cursor=&__rnd=1556799484815"start_urls = [base_url.format(offset)]def parse(self, response):data = json.loads(response.text)if data and 'data' in data:pattern = re.compile('<div.*?list_title_b.*?<a href="(.*?)".*?_blank">(.*?)</a>.*?subinfo S_txt2">(.*?)</span></a>.*?'+ 'S_txt2">(.*?)</span>.*?praised S_ficon W_f16">?</em><em>(.*?)</em>.*?ficon_'+ 'repeat S_ficon W_f16">.*?</em><em>(.*?)</em>.*?forward S_ficon W_f16.*?</em><em>'+ '(.*?)</em>.*?</div>', re.S)result = re.findall(pattern, data.get('data'))for info in result:item = WeiboItem()item['content'] = info[1]item['author'] = info[2]item['publishTime'] = info[3]item['repost'] = info[4]item['comment'] = info[5]item['approve'] = info[6]item['address'] = info[0]yield itemif self.offset < 30:self.offset += 1url = self.base_url.format(self.offset)yield scrapy.Request(url, callback=self.parse)這個解析源代碼的方式沒有使用scrapy提供的xpath或者css解析,而是使用了re包解析,顯得麻煩了點
6.?接下來就是要和django進行交互的代碼編寫了,我們先在scrapy的settings.py文件中添加配置信息:
# 配置python的環境變量 import django os.environ['DJANGO_SETTINGS_MODULE'] = 'DjangoRelateScrapy.settings' django.setup()# 默認為True,此處改為False ROBOTSTXT_OBEY = False# 默認請求頭,我一般習慣加上user-agent 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 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36' }# 開啟我們的管道 ITEM_PIPELINES = {'weibo.pipelines.WeiboPipeline': 300, }7.?在django項目中的setting文件中修改和添加配置(包括數據庫配置):
# 在這里添加上我們生成的app名稱,我的就是最后一個microblog INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','microblog', ] # 連接數據庫的配置 DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'weibo1','USER': 'root','PASSWORD': 'wangqile','HOST': 'localhost','PORT': '3306'} } # 加載static中的靜態文件 STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),os.path.join(BASE_DIR), ]8.?編寫django項目下models.py:
from django.db import models# Create your models here.class HotSpot(models.Model):content = models.CharField(max_length=255)author = models.CharField(max_length=255)publishTime = models.CharField(max_length=255)repost = models.IntegerField()comment = models.IntegerField()approve = models.IntegerField()address = models.URLField()# 排序class Meta:ordering = ['-id']由于django具有站點管理的功能,所以編寫的admin.py文件如下:
from django.contrib import admin# Register your models here. from microblog.models import HotSpot@admin.register(HotSpot) class SpotAdmin(admin.ModelAdmin):# 設置頁面列的名稱list_display = ['pk', 'content', 'author', 'publishTime', 'repost','comment', 'approve', 'address']list_per_page = 10ordering = ('pk',)search_fields = ['content']# 執行動作的位置actions_on_bottom = Trueactions_on_top = False9.?在django根目錄下執行django的數據遷移,生成遷移文件和數據庫表
python manage.py makemigrations python manage.py migrate生成的數據庫表結構如下
10.?下載scrapy-djangoitem工具包:
pip install scrapy-djangoitem具體的關于scrapy-djangoitem信息內容請參考https://github.com/scrapy-plugins/scrapy-djangoitem
11.?在scrapy的items.py中編寫:
import scrapy from scrapy_djangoitem import DjangoItemfrom microblog.models import HotSpotclass WeiboItem(DjangoItem):# define the fields for your item here like:django_model = HotSpotHotSpot就是我們引用的django中的models.py中的一個模型類
12.?在scrapy的pipleline.py中編寫:
class WeiboPipeline(object):def process_item(self, item, spider):# 使用save就是把item存入到了數據庫item.save()return item13.?此時我們可以在scrapy項目下創建一個測試文件,測試是否把我們爬取的數據存入到了數據庫:
編寫的測試文件main.py:
from scrapy.cmdline import executeexecute('scrapy crawl WBlog'.split())直接在測試文件中運行,避免了我們在命令行中去運行爬蟲文件,運行后的結果如下:
太多信息沒法截圖省略了,但我們可以觀察到微博熱點信息已經爬取出來了,而且數據庫中數據也存入進來:
14.?由于我們最終的效果是把微博熱點展示在網頁上,所以我們要在django項目中添加路由,編寫urls.py:
from django.urls import path from . import viewsapp_name = 'microblog'urlpatterns = [path('', views.weibo, name='weibo'),path('detail/<int:num>/', views.detail, name='detail'), ]這個是在app下床架的urls.py,需要在項目下的urls.py中指定下該文件:
from django.contrib import admin from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),path('', include('microblog.urls', namespace="microblog")) ]15.?緊接著編寫好視圖文件views.py:
from django.core.paginator import Paginator from django.http import HttpResponse from django.shortcuts import render# Create your views here. from microblog.models import HotSpot# 這個函數不用關注 def weibo(request):return render(request, 'weibo.html')def detail(request, num):list = HotSpot.objects.all()# 實現分頁功能paginator = Paginator(list, 8)if num > 100:num = 1page = paginator.page(num)return render(request, 'weibo.html', {'spotList': page})16.?最后編寫我們的前端頁面weibo.html:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>微博首頁</title><link rel="stylesheet" type="text/css" href="/static/css/a.css"> </head> <body><div class="topDiv"><img src="/static/img/weibo.png" ><p> 微博熱點自動提取軟件開發 </p><div><input type="image" name="熱點提取" src="/static/img/jiji.png"><span class="oneSpan">←←←</span><span class="twoSpan">點這里</span></div></div><div class="leftDiv"><ul><li><a href="#">熱點</a></li><li><a href="/detail/1760">頭條</a></li><li><a href="#">新鮮事</a></li><li><a href="#">榜單</a></li><li><a href="#">搞笑</a></li><li><a href="#">社會</a></li><li><a href="#">時尚</a></li></ul></div><div class="spotDiv"><ul>{% for item in spotList %}<div><li class="oneLi"><a href="{{ item.address }}" target="_blank">{{ item.content }}</a></li><br/><br/><li>{{ item.author }}  {{ item.publishTime }}</li>       <li class="twoLi"><input type="image" src="/static/img/approve.png"> {{ item.approve }} <input type="image" src="/static/img/comment.png"> {{ item.comment }} <input type="image" src="/static/img/repost.png"> {{ item.repost }}</li></div>{% endfor %}</ul><ul class="oneUl">{% for index in spotList.paginator.page_range %}{% if index == spotList.number %} <li>{{ index }}</li>{% else %} <li><a href="/detail/{{ index }}/">{{ index }}</a></li>{% endif %}{% endfor %}</ul></div> </body> </html>外部靜態文件夾下的css文件如下:
.topDiv {height: 80px; width: 100%;border-bottom: 2px solid #ebebeb;box-shadow:0px 5px 0px 0px rgba(245, 245, 245, 0.45);}.topDiv p {font-family:"Microsoft YaHei",Tahoma,Verdana,SimSun;font-size: 25px;text-align: center;color: #bdae9c;position: relative;left: 400px; top: 0px;display: inline-block;}.oneSpan {color: red;font-weight: bold;font-size: 30px;}.topDiv div {position: relative;left: 650px; top: 0px;display: inline-block;}.twoSpan {font-size: 23px;color: burlywood;}.oneSpan, .twoSpan {position: relative;left: 8px; top: -15px;}.leftDiv {width: 13%;}ul li {list-style: none;}.leftDiv ul li a {display: block;font-size: 18px;color: #000;height: 60px;line-height: 50px;border-radius: 3px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;padding: 0 8px;text-align: center;text-decoration: none;}.leftDiv ul li a:hover{background-color: #ff4418;color: white;}.spotDiv {position: absolute;top: 16%; left: 19%;width: 1000px;border-left-color: #ff122d;}.spotDiv ul li {display: inline-block;}.spotDiv ul div {height: 80px;border-bottom: 1px solid #ebebeb;box-shadow:0px 1px 0px 0px rgba(245, 245, 245, 0.45);background-color: #fbfff6;}.oneLi a{font-size: 20px;text-decoration: none;color: #ff6466;font-weight: bold;}.twoLi {position: absolute;left: 70%;}.twoLi input {width: 16px; height: 16px;}.oneUl li a{text-decoration: none;color: black;background-color: #00c1c1;}4.?效果展示
5.?碰到的問題及解決思路(重要)
1.?當初碰到的第一個問題就是django和scrapy通過scrapy-djangoitem無法進行關聯,因為python的環境變量是在不懂的怎么配,參考了網上的很多教程,最后找到了衣蛾比較簡單的方法,就是在django的根目錄下直接創建scrapy項目,這樣我們就省卻了一步在scrapy的settings.py文件中配置django項目文件路徑,只需要加載下django的setting文件即可
解決方式來源于這個博主的文章:https://juejin.im/post/5a2605f251882535c56cc2e6
2.?解決了上面一個問題之后,發現我們需要在命令行中編寫scrapy crawl?WBlog命令爬蟲文件爬取信息,這種方式還是太low,所以scrapy提供了一個cmdline包,編寫一個python文件直接在函數中執行該命令,我們只需要運行這個python文件即可:
3.?當數據存入數據庫時,發現存入的數據太少了,本來存入幾百條的數據只存入了幾十條,最終在編寫的爬蟲類WBlog.py中找到問題:
我把紅線標記的地方寫到了for循環外,這就直接導致我每爬取一頁的數據,最終一頁八條的數據只存入數據庫一條,究其原因,是因為每一條數據都需要創建一個item = WeiboItem(),寫在for循環外相當于我們一頁就創建了一個item,所以存入數據庫中也就一條數據,而不是一頁八條的數據
6.?總結
這個是我的畢設,我比較后悔的是用了很多的框架。不可否認,框架確實能提高我們的編程效率和代碼可讀性,但對于小的項目來講,我們應該避免使用很多的框架,因為框架之間的關聯起來有時是聽麻煩挺坑的,比如我就在django和scrapy關聯上卡死了很久,于是在最后編寫前端頁面的時候沒有使用bootstrap框架,因為實在沒必要,大材小用了,最終,我們在處理Bug時一定放平心態,切記切記不要急躁!!
項目的源代碼:鏈接: https://pan.baidu.com/s/16oTAsnctVK4HLuABBCNw0g 提取碼: n3hp?
總結
以上是生活随笔為你收集整理的Django+Scrapy完成微博首页热点的提取和网页显示的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 选眼镜必知知识
- 下一篇: 比较好用的读书方法分享