首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >优化此.NET爬虫算法的技巧

优化此.NET爬虫算法的技巧
EN

Stack Overflow用户
提问于 2015-02-07 17:26:23
回答 2查看 114关注 0票数 1

我正在编写类似于web爬虫的东西,它的引擎遵循以下步骤:

  1. 阅读Rss链接(论据)
  2. 定义Rss项的列表
  3. 通过单独的查询检查数据库(SQL SERVER)中的每个链接是否存在
  4. 如果链接是新链接,它将通过单独的查询将字段插入到DB。 公共子() Dim MyTickHandler() Dim NewItems作为新列表( Structures.RSSItem) Dim创建为Boolean = False NewItems = RssReader.ParseRssFile(RssURL) Dim connString = Configs.NewsDBConnection Dim myConnection As SqlConnection =新的Structures.RSSItem Security=SSPI;;Connection Timeout=45;( Size= 300") myConnection.Open() NewItems Dim cmdString As String = "SELECT id FROM post with (nolock)其中链接像‘& item.link.Trim.ToLower &’'“Dim TheCommand As SqlCommand =新SqlCommand(cmdString,如果结果是空值,则myConnection =新SqlCommand(“插入到posts (链接)值('”& item.link.ToLower.Trim &‘’)) TheCommand.Connection =myConnection TheCommand.ExecuteNonQuery() TheCommand =新SqlCommand(“插入队列(链接、描述、站点、标题、类别)值”(‘& item.link.ToLower.Trim &’),‘’& StringToBase64(item.description) & "','“& RssSite &”,‘’& StringToBase64(item.title) &‘,’‘& RssCategory &’‘)) TheCommand.Connection = myConnection TheCommand.ExecuteNonQuery(),如果TheCommand.Dispose() Next myConnection.Close() myConnection.Dispose(MyConnection) SqlConnection.ClearPool(myConnection)结束

这是一次通话的最佳选择。

但是我有一些关于150个的链接,我应该每2分钟通过线程检查其中的每个,因此通过增加查询的装载,这个过程和server不会响应和应用程序崩溃!!

我尝试了一些技巧,比如增加sql服务器响应超时,但这一点也没有帮助。

对于这个过程,有什么更好的方法或建议吗?

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-02-07 17:43:51

  • 在for-each循环之外,只进行一次提取:

SELECT id, link FROM posts with (nolock) WHERE link in (@listOfLowerCaseLinks)

代码语言:javascript
复制
Dim myListOfLinks As New List(Of String)
...
TheCommand.Parameters.AddWithValue("@listOfLowerCaseLinks", myListOfLinks)
  • 将插入(整个for-每个循环)的整个操作包装到一个sql事务中。这样,数据库就不必在中间提交。
票数 1
EN

Stack Overflow用户

发布于 2015-02-07 20:23:09

我建议您将表值参数传递给此任务的存储过程。这将允许将整个列表插入到单个调用中。下面是一个示例,您可以根据实际的列长度进行调整。重要的是在posts表的链接列上有一个索引。在本例中,我假设链接是唯一的。

创建表类型和proc的type:

代码语言:javascript
复制
CREATE TYPE dbo.linkInfo AS TABLE(
     link varchar(255) NOT NULL PRIMARY KEY
    ,descrip varchar(255)
    ,title varchar(255)
    );
GO

ALTER PROC dbo.usp_InsertRssItems
     @site varchar(255)
    ,@category varchar(255)
    ,@linkInfo dbo.linkInfo READONLY
AS

SET NOCOUNT ON;

DECLARE @InsertedPosts TABLE(link varchar(255));

INSERT INTO dbo.posts(link)
OUTPUT inserted.link INTO @InsertedPosts
SELECT link
FROM @linkInfo AS li
WHERE NOT EXISTS(
    SELECT *
    FROM dbo.posts AS p
    WHERE p.link = li.link
    );

INSERT INTO dbo.queue(link,descrip,site,title,category)
SELECT li.link, li.descrip, @site,li. title, @category
FROM @linkInfo AS li
WHERE EXISTS(
    SELECT *
    FROM @InsertedPosts AS ip
    WHERE ip.link = li.link
    );
GO

示例VB.NET代码:

代码语言:javascript
复制
Sub MyTickHandler()

    Dim NewItems As New List(Of Structures.RssItem)
    Dim founded As Boolean = False

    NewItems = RssReader.ParseRssFile(RssURL)

    Dim dt = getNewRssItemDataTable(NewItems)

    Dim connString = Configs.NewsDBConnection
    Dim myConnection As SqlConnection = New SqlConnection("Server=localhost;Database=db;Integrated Security=SSPI;;Connection Timeout=45;Max Pool Size= 300")
    Dim TheCommand As SqlCommand = New SqlCommand("dbo.usp_InsertRssItems", myConnection)
    TheCommand.Parameters.Add(New SqlParameter("@site", SqlDbType.VarChar, 255)).Value = "z"
    TheCommand.Parameters.Add(New SqlParameter("@category", SqlDbType.VarChar, 255)).Value = "z"
    TheCommand.Parameters.Add(New SqlParameter("@linkInfo", SqlDbType.Structured)).Value = dt
    TheCommand.CommandType = CommandType.StoredProcedure

    myConnection.Open()
    TheCommand.ExecuteNonQuery()

    myConnection.Close()
    myConnection.Dispose()

End Sub

Private Function getNewRssItemDataTable(NewRssItems As List(Of Structures.RssItem)) As DataTable

    Dim dt As New DataTable
    dt.Columns.Add("link", GetType(String)).MaxLength = 255
    dt.Columns.Add("descrip", GetType(String)).MaxLength = 255
    dt.Columns.Add("title", GetType(String)).MaxLength = 255

    For Each NewRssItem In NewRssItems
        Dim row = dt.NewRow
        dt.Rows.Add(row)
        row(0) = NewRssItem.link
        row(1) = NewRssItem.description
        row(2) = NewRssItem.title

    Next NewRssItem

    Return dt

End Function

编辑:

我看到你提到过你想要一个SqlBulkCopy的例子。如果插入是无条件的,则可以使用以下技术:

代码语言:javascript
复制
Sub executeBulkInsert(connectionString As String, site As String, category As String, NewRssItems As List(Of Structures.RssItem))

    Dim dt As New DataTable

    dt.Columns.Add("link", GetType(String)).MaxLength = 255
    dt.Columns.Add("descrip", GetType(String)).MaxLength = 255
    dt.Columns.Add("site", GetType(String)).MaxLength = 255
    dt.Columns.Add("title", GetType(String)).MaxLength = 255
    dt.Columns.Add("category", GetType(String)).MaxLength = 255

    For Each NewRssItem In NewRssItems
        Dim row = dt.NewRow
        dt.Rows.Add(row)
        row(0) = site
        row(1) = category
        row(2) = NewRssItem.link
        row(3) = NewRssItem.description
        row(4) = NewRssItem.title

    Next NewRssItem

    Dim bcp = New SqlBulkCopy(connectionString)
    bcp.DestinationTableName = "dbo.queue"

    bcp.WriteToServer(dt)

End Sub
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28385122

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档