This commit is contained in:
Christopher Meinhold 2024-09-15 21:43:55 +02:00
parent 5a5b8132f8
commit 8604066f77
18 changed files with 1832 additions and 0 deletions

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35222.181
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grosshandel2", "Grosshandel2\Grosshandel2.csproj", "{5D9FD5F3-4DDE-4E45-9959-04AA4F5C3518}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5D9FD5F3-4DDE-4E45-9959-04AA4F5C3518}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5D9FD5F3-4DDE-4E45-9959-04AA4F5C3518}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5D9FD5F3-4DDE-4E45-9959-04AA4F5C3518}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5D9FD5F3-4DDE-4E45-9959-04AA4F5C3518}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E7F8D8D2-C3A7-4A56-A1E4-C87D3096EEC0}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,11 @@
namespace Grosshandel2
{
public class Artikel
{
public int ArtikelId { get; set; }
public string Name { get; set; }
public decimal Preis { get; set; }
public decimal Grosshandelspreis { get; set; }
public byte[] Bild { get; set; }
}
}

View File

@ -0,0 +1,132 @@
using System;
using System.Data;
using MySql.Data.MySqlClient;
namespace Grosshandel2
{
public class DatabaseManager
{
private string _connectionString = "Server=192.168.178.201;Database=grosshandel;User ID=root;Password=1td5rugut8;";
public DataTable GetArtikelListe()
{
using (var connection = new MySqlConnection(_connectionString))
{
var query = @"SELECT a.ArtikelId, a.Name, p.Preis, p.Grosshandelspreis
FROM Artikel a
JOIN Preise p ON a.ArtikelId = p.ArtikelId";
using (var adapter = new MySqlDataAdapter(query, connection))
{
var dataTable = new DataTable();
adapter.Fill(dataTable);
return dataTable;
}
}
}
public void AddArtikel(Artikel artikel, byte[] bild)
{
using (var connection = new MySqlConnection(_connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
// Füge den Artikel hinzu
var insertArtikelQuery = "INSERT INTO Artikel (Name, Bild) VALUES (@Name, @Bild); SELECT LAST_INSERT_ID();";
var command = new MySqlCommand(insertArtikelQuery, connection, transaction);
command.Parameters.AddWithValue("@Name", artikel.Name);
command.Parameters.AddWithValue("@Bild", bild ?? (object)DBNull.Value);
// Hole die zuletzt eingefügte ArtikelId
var artikelId = Convert.ToInt32(command.ExecuteScalar());
// Füge den Preis hinzu
var insertPreisQuery = "INSERT INTO Preise (ArtikelId, Preis, Grosshandelspreis) VALUES (@ArtikelId, @Preis, @Grosshandelspreis);";
command = new MySqlCommand(insertPreisQuery, connection, transaction);
command.Parameters.AddWithValue("@ArtikelId", artikelId);
command.Parameters.AddWithValue("@Preis", artikel.Preis);
command.Parameters.AddWithValue("@Grosshandelspreis", artikel.Grosshandelspreis);
command.ExecuteNonQuery();
transaction.Commit();
}
}
}
public void UpdateArtikel(Artikel artikel, byte[] bild)
{
using (var connection = new MySqlConnection(_connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
var updateArtikelQuery = "UPDATE Artikel SET Name = @Name, Bild = @Bild WHERE ArtikelId = @ArtikelId;";
var command = new MySqlCommand(updateArtikelQuery, connection, transaction);
command.Parameters.AddWithValue("@Name", artikel.Name);
command.Parameters.AddWithValue("@Bild", bild ?? (object)DBNull.Value);
command.Parameters.AddWithValue("@ArtikelId", artikel.ArtikelId);
command.ExecuteNonQuery();
var updatePreisQuery = "UPDATE Preise SET Preis = @Preis, Grosshandelspreis = @Grosshandelspreis WHERE ArtikelId = @ArtikelId;";
command = new MySqlCommand(updatePreisQuery, connection, transaction);
command.Parameters.AddWithValue("@Preis", artikel.Preis);
command.Parameters.AddWithValue("@Grosshandelspreis", artikel.Grosshandelspreis);
command.Parameters.AddWithValue("@ArtikelId", artikel.ArtikelId);
command.ExecuteNonQuery();
transaction.Commit();
}
}
}
public void DeleteArtikel(int artikelId)
{
using (var connection = new MySqlConnection(_connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
var deletePreisQuery = "DELETE FROM Preise WHERE ArtikelId = @ArtikelId;";
var command = new MySqlCommand(deletePreisQuery, connection, transaction);
command.Parameters.AddWithValue("@ArtikelId", artikelId);
command.ExecuteNonQuery();
var deleteArtikelQuery = "DELETE FROM Artikel WHERE ArtikelId = @ArtikelId;";
command = new MySqlCommand(deleteArtikelQuery, connection, transaction);
command.Parameters.AddWithValue("@ArtikelId", artikelId);
command.ExecuteNonQuery();
transaction.Commit();
}
}
}
public byte[] GetBildByArtikelId(int artikelId)
{
byte[] bild = null;
using (var connection = new MySqlConnection(_connectionString))
{
connection.Open();
var query = "SELECT Bild FROM Artikel WHERE ArtikelId = @ArtikelId";
using (var command = new MySqlCommand(query, connection))
{
command.Parameters.AddWithValue("@ArtikelId", artikelId);
using (var reader = command.ExecuteReader())
{
if (reader.Read())
{
bild = reader["Bild"] as byte[];
}
}
}
}
return bild;
}
}
}

View File

@ -0,0 +1,158 @@
namespace Grosshandel2
{
partial class FrmMain
{
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.DataGridView dataGridView1;
private System.Windows.Forms.TextBox txtName;
private System.Windows.Forms.NumericUpDown numericPreis;
private System.Windows.Forms.NumericUpDown numericGrosshandelspreis;
private System.Windows.Forms.Button btnAdd;
private System.Windows.Forms.Button btnUpdate;
private System.Windows.Forms.Button btnDelete;
private System.Windows.Forms.PictureBox pictureBox;
private System.Windows.Forms.TextBox txtBildPfad;
private System.Windows.Forms.Button btnBrowseImage;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.txtName = new System.Windows.Forms.TextBox();
this.numericPreis = new System.Windows.Forms.NumericUpDown();
this.numericGrosshandelspreis = new System.Windows.Forms.NumericUpDown();
this.btnAdd = new System.Windows.Forms.Button();
this.btnUpdate = new System.Windows.Forms.Button();
this.btnDelete = new System.Windows.Forms.Button();
this.pictureBox = new System.Windows.Forms.PictureBox();
this.txtBildPfad = new System.Windows.Forms.TextBox();
this.btnBrowseImage = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numericPreis)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numericGrosshandelspreis)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox)).BeginInit();
this.SuspendLayout();
//
// dataGridView1
//
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Location = new System.Drawing.Point(12, 12);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.RowHeadersWidth = 51;
this.dataGridView1.RowTemplate.Height = 24;
this.dataGridView1.Size = new System.Drawing.Size(776, 150);
this.dataGridView1.TabIndex = 0;
this.dataGridView1.SelectionChanged += new System.EventHandler(this.dataGridView1_SelectionChanged);
//
// txtName
//
this.txtName.Location = new System.Drawing.Point(12, 200);
this.txtName.Name = "txtName";
this.txtName.Size = new System.Drawing.Size(200, 22);
this.txtName.TabIndex = 1;
//
// numericPreis
//
this.numericPreis.DecimalPlaces = 2;
this.numericPreis.Location = new System.Drawing.Point(12, 250);
this.numericPreis.Name = "numericPreis";
this.numericPreis.Size = new System.Drawing.Size(120, 22);
this.numericPreis.TabIndex = 2;
//
// numericGrosshandelspreis
//
this.numericGrosshandelspreis.DecimalPlaces = 2;
this.numericGrosshandelspreis.Location = new System.Drawing.Point(12, 300);
this.numericGrosshandelspreis.Name = "numericGrosshandelspreis";
this.numericGrosshandelspreis.Size = new System.Drawing.Size(120, 22);
this.numericGrosshandelspreis.TabIndex = 3;
//
// btnAdd
//
this.btnAdd.Location = new System.Drawing.Point(250, 200);
this.btnAdd.Name = "btnAdd";
this.btnAdd.Size = new System.Drawing.Size(75, 23);
this.btnAdd.TabIndex = 4;
this.btnAdd.Text = "Hinzufügen";
this.btnAdd.UseVisualStyleBackColor = true;
this.btnAdd.Click += new System.EventHandler(this.btnAdd_Click);
//
// btnUpdate
//
this.btnUpdate.Location = new System.Drawing.Point(250, 250);
this.btnUpdate.Name = "btnUpdate";
this.btnUpdate.Size = new System.Drawing.Size(75, 23);
this.btnUpdate.TabIndex = 5;
this.btnUpdate.Text = "Aktualisieren";
this.btnUpdate.UseVisualStyleBackColor = true;
this.btnUpdate.Click += new System.EventHandler(this.btnUpdate_Click);
//
// btnDelete
//
this.btnDelete.Location = new System.Drawing.Point(250, 300);
this.btnDelete.Name = "btnDelete";
this.btnDelete.Size = new System.Drawing.Size(75, 23);
this.btnDelete.TabIndex = 6;
this.btnDelete.Text = "Löschen";
this.btnDelete.UseVisualStyleBackColor = true;
this.btnDelete.Click += new System.EventHandler(this.btnDelete_Click);
//
// pictureBox
//
this.pictureBox.Location = new System.Drawing.Point(400, 200);
this.pictureBox.Name = "pictureBox";
this.pictureBox.Size = new System.Drawing.Size(200, 200);
this.pictureBox.TabIndex = 7;
this.pictureBox.TabStop = false;
this.pictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
//
// txtBildPfad
//
this.txtBildPfad.Location = new System.Drawing.Point(400, 150);
this.txtBildPfad.Name = "txtBildPfad";
this.txtBildPfad.Size = new System.Drawing.Size(200, 22);
this.txtBildPfad.TabIndex = 8;
//
// btnBrowseImage
//
this.btnBrowseImage.Location = new System.Drawing.Point(625, 150);
this.btnBrowseImage.Name = "btnBrowseImage";
this.btnBrowseImage.Size = new System.Drawing.Size(75, 23);
this.btnBrowseImage.TabIndex = 9;
this.btnBrowseImage.Text = "Durchsuchen";
this.btnBrowseImage.UseVisualStyleBackColor = true;
this.btnBrowseImage.Click += new System.EventHandler(this.btnBrowseImage_Click);
//
// FrmMain
//
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.btnBrowseImage);
this.Controls.Add(this.txtBildPfad);
this.Controls.Add(this.pictureBox);
this.Controls.Add(this.btnDelete);
this.Controls.Add(this.btnUpdate);
this.Controls.Add(this.btnAdd);
this.Controls.Add(this.numericGrosshandelspreis);
this.Controls.Add(this.numericPreis);
this.Controls.Add(this.txtName);
this.Controls.Add(this.dataGridView1);
this.Name = "FrmMain";
this.Text = "Artikelverwaltung";
this.Load += new System.EventHandler(this.FrmMain_Load);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numericPreis)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numericGrosshandelspreis)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
}
}

View File

@ -0,0 +1,161 @@
using System;
using System.Data;
using System.Windows.Forms;
namespace Grosshandel2
{
public partial class FrmMain : Form
{
private DatabaseManager _dbManager;
private Artikel _currentArtikel;
public FrmMain()
{
InitializeComponent();
_dbManager = new DatabaseManager();
}
private void FrmMain_Load(object sender, EventArgs e)
{
LoadArtikelData();
}
private void LoadArtikelData()
{
try
{
var artikelTable = _dbManager.GetArtikelListe();
if (artikelTable != null)
{
dataGridView1.DataSource = artikelTable;
}
else
{
MessageBox.Show("Keine Artikel gefunden.");
}
}
catch (Exception ex)
{
MessageBox.Show($"Fehler beim Laden der Artikel: {ex.Message}");
}
}
private void btnAdd_Click(object sender, EventArgs e)
{
// Erstelle ein neues Artikel-Objekt
var artikel = new Artikel
{
Name = txtName.Text,
Preis = numericPreis.Value,
Grosshandelspreis = numericGrosshandelspreis.Value
};
// Lade das Bild, falls ein Bildpfad angegeben ist
byte[] bildBytes = null;
if (!string.IsNullOrEmpty(txtBildPfad.Text))
{
bildBytes = LoadImageFromFile(txtBildPfad.Text);
}
try
{
// Füge den Artikel zur Datenbank hinzu
_dbManager.AddArtikel(artikel, bildBytes);
// Lade die Artikel-Daten neu
LoadArtikelData();
// Bestätigungsnachricht
MessageBox.Show("Artikel erfolgreich hinzugefügt.");
}
catch (Exception ex)
{
MessageBox.Show("Fehler beim Hinzufügen des Artikels: " + ex.Message);
}
}
private void btnUpdate_Click(object sender, EventArgs e)
{
if (_currentArtikel != null)
{
_currentArtikel.Name = txtName.Text;
_currentArtikel.Preis = numericPreis.Value;
_currentArtikel.Grosshandelspreis = numericGrosshandelspreis.Value;
_currentArtikel.Bild = File.ReadAllBytes(txtBildPfad.Text);
_dbManager.UpdateArtikel(_currentArtikel, _currentArtikel.Bild);
LoadArtikelData();
}
}
private void btnDelete_Click(object sender, EventArgs e)
{
if (_currentArtikel != null)
{
_dbManager.DeleteArtikel(_currentArtikel.ArtikelId);
LoadArtikelData();
_currentArtikel = null;
ClearForm();
}
}
private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
if (dataGridView1.SelectedRows.Count > 0)
{
var selectedRow = dataGridView1.SelectedRows[0];
var artikelId = Convert.ToInt32(selectedRow.Cells["ArtikelId"].Value);
// Abrufen des Bildes aus der Datenbank
var bildBytes = _dbManager.GetBildByArtikelId(artikelId);
if (bildBytes != null && bildBytes.Length > 0)
{
using (var ms = new MemoryStream(bildBytes))
{
pictureBox.Image = Image.FromStream(ms);
}
}
else
{
pictureBox.Image = null;
}
txtName.Text = selectedRow.Cells["Name"].Value.ToString();
numericPreis.Value = Convert.ToDecimal(selectedRow.Cells["Preis"].Value);
numericGrosshandelspreis.Value = Convert.ToDecimal(selectedRow.Cells["Grosshandelspreis"].Value);
txtBildPfad.Text = string.Empty; // Optional, falls du den Bildpfad anzeigen möchtest
}
}
private void ClearForm()
{
txtName.Clear();
numericPreis.Value = 0;
numericGrosshandelspreis.Value = 0;
txtBildPfad.Clear();
pictureBox.Image = null;
}
private void btnBrowseImage_Click(object sender, EventArgs e)
{
using (var openFileDialog = new OpenFileDialog())
{
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
txtBildPfad.Text = openFileDialog.FileName;
pictureBox.Image = Image.FromFile(openFileDialog.FileName);
}
}
}
private byte[] LoadImageFromFile(string filePath)
{
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
{
return null;
}
return File.ReadAllBytes(filePath);
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySql.Data" Version="9.0.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,17 @@
namespace Grosshandel2
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new FrmMain());
}
}
}

63
webCrawlerGoogle/.gitattributes vendored Normal file
View File

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

363
webCrawlerGoogle/.gitignore vendored Normal file
View File

@ -0,0 +1,363 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.10.35122.118
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "webCrawlerGoogle", "webCrawlerGoogle\webCrawlerGoogle.csproj", "{36E507D2-6D2C-43DD-9E30-F7E151018942}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{36E507D2-6D2C-43DD-9E30-F7E151018942}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{36E507D2-6D2C-43DD-9E30-F7E151018942}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36E507D2-6D2C-43DD-9E30-F7E151018942}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36E507D2-6D2C-43DD-9E30-F7E151018942}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FB32F52A-3116-4EB2-A3D9-B6435A5B7A2E}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,110 @@
namespace webCrawlerGoogle
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
txtCategory = new TextBox();
txtCity = new TextBox();
btnSearch = new Button();
lstResults = new ListBox();
lblFortschritt = new Label();
SuspendLayout();
//
// txtCategory
//
txtCategory.Location = new Point(14, 14);
txtCategory.Margin = new Padding(4, 3, 4, 3);
txtCategory.Name = "txtCategory";
txtCategory.PlaceholderText = "Rubrik (z.B. Restaurant)";
txtCategory.Size = new Size(303, 23);
txtCategory.TabIndex = 0;
//
// txtCity
//
txtCity.Location = new Point(14, 44);
txtCity.Margin = new Padding(4, 3, 4, 3);
txtCity.Name = "txtCity";
txtCity.PlaceholderText = "Stadt (z.B. Berlin)";
txtCity.Size = new Size(303, 23);
txtCity.TabIndex = 1;
//
// btnSearch
//
btnSearch.Location = new Point(14, 74);
btnSearch.Margin = new Padding(4, 3, 4, 3);
btnSearch.Name = "btnSearch";
btnSearch.Size = new Size(303, 27);
btnSearch.TabIndex = 2;
btnSearch.Text = "Suchen";
btnSearch.UseVisualStyleBackColor = true;
btnSearch.Click += btnSearch_Click;
//
// lstResults
//
lstResults.FormattingEnabled = true;
lstResults.ItemHeight = 15;
lstResults.Location = new Point(14, 107);
lstResults.Margin = new Padding(4, 3, 4, 3);
lstResults.Name = "lstResults";
lstResults.Size = new Size(303, 169);
lstResults.TabIndex = 3;
//
// lblFortschritt
//
lblFortschritt.AutoSize = true;
lblFortschritt.Location = new Point(18, 290);
lblFortschritt.Name = "lblFortschritt";
lblFortschritt.Size = new Size(10, 15);
lblFortschritt.TabIndex = 4;
lblFortschritt.Text = ".";
//
// Form1
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(334, 350);
Controls.Add(lblFortschritt);
Controls.Add(lstResults);
Controls.Add(btnSearch);
Controls.Add(txtCity);
Controls.Add(txtCategory);
Margin = new Padding(4, 3, 4, 3);
Name = "Form1";
Text = "Google Business Suche";
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox txtCategory;
private System.Windows.Forms.TextBox txtCity;
private System.Windows.Forms.Button btnSearch;
private System.Windows.Forms.ListBox lstResults;
private Label lblFortschritt;
}
}

View File

@ -0,0 +1,267 @@
using MySql.Data.MySqlClient;
using HtmlAgilityPack;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Diagnostics;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
namespace webCrawlerGoogle
{
public partial class Form1 : Form
{
private static string connectionString = "Server=192.168.178.201;Database=domainchecker;User ID=root;Password=1td5rugut8;";
private static int searchCounter = 0;
private static int maxSearchesBeforeVPNChange = 20; // Anzahl der Suchanfragen, bevor der VPN gewechselt wird
private static int pauseAfterEachSearchMs = 500; // Pause nach jeder Suchanfrage (2 Sekunden)
private static int longPauseAfterBatchMs = 60000; // Längere Pause nach einer Reihe von Suchanfragen (1 Minute)
private static int fortschritt = 0;
public Form1()
{
InitializeComponent();
}
private async void btnSearch_Click(object sender, EventArgs e)
{
var searchParams = LoadSearchParamsFromDatabase();
foreach (var param in searchParams)
{
string category = param.Rubrik;
string city = param.Stadt;
//AppendToOutput($"Suche nach: {category} in {city}");
await ScrapeGoogleResults(category, city);
searchCounter++;
if (searchCounter >= maxSearchesBeforeVPNChange)
{
ChangeVPN();
searchCounter = 0;
//AppendToOutput("Längere Pause nach VPN-Wechsel...");
await Task.Delay(longPauseAfterBatchMs);
}
else
{
//AppendToOutput("Kurze Pause nach Suchanfrage...");
await Task.Delay(pauseAfterEachSearchMs);
}
}
}
private async Task ScrapeGoogleResults(string category, string city)
{
string query = $"{category}+in+{city}";
string searchUrl = $"https://www.google.com/search?q=" + query;
//$"https://www.google.com/search?q={Uri.EscapeDataString(query)}";
var options = new ChromeOptions();
options.AddArgument("headless");
options.AddArgument("disable-gpu");
using (var driver = new ChromeDriver(options))
{
driver.Navigate().GoToUrl(searchUrl);
await Task.Delay(2000); // Warte ein wenig, damit die Seite vollständig geladen wird
var titleNodes = driver.FindElements(By.XPath("//h3[@class='LC20lb MBeuO DKV0Md']"));
if (titleNodes != null && titleNodes.Count > 0)
{
foreach (var node in titleNodes)
{
// Hier könntest du auch die zugehörige URL extrahieren
var parent = node.FindElement(By.XPath("./ancestor::a"));
if (parent != null)
{
string url = parent.GetAttribute("href");
string cleanedUrl = CleanUrl(url);
if (!CheckIfUrlExistsInDatabase(cleanedUrl))
{
fortschritt++;
SaveUrlToDatabase(cleanedUrl, city, category);
AppendToOutput(cleanedUrl);
lblFortschritt.Text = $"Aktuell hinzugefügt Anzahl {fortschritt}";
Application.DoEvents();
}
}
}
}
else
{
AppendToOutput("Keine Titel gefunden.");
}
}
}
bool CheckIfUrlExistsInDatabase(string url)
{
using (MySqlConnection conn = new MySqlConnection(connectionString))
{
conn.Open();
string query = "SELECT COUNT(*) FROM webCrawler WHERE webseite = @url";
using (MySqlCommand cmd = new MySqlCommand(query, conn))
{
cmd.Parameters.AddWithValue("@url", url);
int count = Convert.ToInt32(cmd.ExecuteScalar());
return count > 0;
}
}
}
void SaveUrlToDatabase(string url, string city, string category)
{
using (MySqlConnection conn = new MySqlConnection(connectionString))
{
conn.Open();
string query = "INSERT INTO webCrawler(email, webseite, stadt, rubrik) VALUES(@value1, @value2, @value3, @value4)";
using (MySqlCommand cmd = new MySqlCommand(query, conn))
{
cmd.Parameters.AddWithValue("@value1", ""); // Leere E-Mail, da nicht angegeben
cmd.Parameters.AddWithValue("@value2", url);
cmd.Parameters.AddWithValue("@value3", city);
cmd.Parameters.AddWithValue("@value4", category);
cmd.ExecuteNonQuery();
}
}
}
static string CleanUrl(string url)
{
// Uri-Objekt erstellen, um die URL zu parsen
Uri uri = new Uri(url);
// Entfernen von "www."
string host = uri.Host.Replace("www.", "");
// Zusammensetzen der bereinigten URL
string cleanedUrl = $"{host}";
return cleanedUrl;
}
private async void ChangeVPN()
{
AppendToOutput("Wechsel des VPN-Servers...");
// VPN trennen
ExecuteCommand("net stop nordvpn-service");
await Task.Delay(30000); // Warte, um sicherzustellen, dass der Dienst vollständig gestoppt wird
// VPN wieder verbinden
ExecuteCommand("net start nordvpn-service");
await Task.Delay(30000); // Warte, um sicherzustellen, dass der Dienst vollständig gestartet wird
AppendToOutput("VPN-Server gewechselt.");
}
private void ExecuteCommand(string command)
{
var processInfo = new ProcessStartInfo("cmd.exe", "/c " + command)
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
};
using (var process = Process.Start(processInfo))
{
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
process.WaitForExit();
if (!string.IsNullOrEmpty(output))
{
AppendToOutput("Output: " + output);
}
if (!string.IsNullOrEmpty(error))
{
AppendToOutput("Fehler: " + error);
}
if (process.ExitCode != 0)
{
AppendToOutput("Der Befehl '" + command + "' wurde nicht erfolgreich ausgeführt.");
}
}
}
private void AppendToOutput(string text)
{
if (InvokeRequired)
{
Invoke(new Action(() => AppendToOutput(text)));
return;
}
lstResults.Items.Add(text + Environment.NewLine);
}
private List<SearchParam> LoadSearchParamsFromDatabase()
{
var searchParams = new List<SearchParam>();
using (MySqlConnection conn = new MySqlConnection(connectionString))
{
conn.Open();
// Städte aus der Tabelle Staedte laden
var staedte = new List<string>();
string queryStaedte = "SELECT staedte FROM staedte";
using (MySqlCommand cmdStaedte = new MySqlCommand(queryStaedte, conn))
{
using (MySqlDataReader readerStaedte = cmdStaedte.ExecuteReader())
{
while (readerStaedte.Read())
{
staedte.Add(readerStaedte.GetString("staedte"));
}
}
}
// Rubriken aus der Tabelle Rubriken laden
var rubriken = new List<string>();
string queryRubriken = "SELECT rubriken FROM rubriken";
using (MySqlCommand cmdRubriken = new MySqlCommand(queryRubriken, conn))
{
using (MySqlDataReader readerRubriken = cmdRubriken.ExecuteReader())
{
while (readerRubriken.Read())
{
rubriken.Add(readerRubriken.GetString("rubriken"));
}
}
}
// Kombiniere jede Rubrik mit jeder Stadt und füge sie zur Liste hinzu
foreach (var stadt in staedte)
{
foreach (var rubrik in rubriken)
{
searchParams.Add(new SearchParam
{
Rubrik = rubrik,
Stadt = stadt
});
}
}
}
return searchParams;
}
}
public class SearchParam
{
public string Rubrik { get; set; }
public string Stadt { get; set; }
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,17 @@
namespace webCrawlerGoogle
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
}
}

View File

@ -0,0 +1,198 @@
NUGET:
Install-Package Selenium.WebDriver
Install-Package Selenium.WebDriver.ChromeDriver
private const string ApiKey = "GELÖSCHT"; //"AIzaSyCjdysuuyc2bs4ikqT8xyIpPJHiDZ4CEo4"; // Füge hier deinen API-Schlüssel ein
private string connectionString = "Server=192.168.178.201;Database=domainchecker;User ID=root;Password=1td5rugut8;";
public Form1()
{
InitializeComponent();
}
private async void btnSearch_Click(object sender, EventArgs e)
{
var searchParams = LoadSearchParamsFromDatabase();
foreach (var param in searchParams)
{
string category = param.Rubrik;
string city = param.Stadt;
string requestUri = $"https://maps.googleapis.com/maps/api/place/textsearch/json?query={category}+in+{city}&key={ApiKey}";
await FetchResults(requestUri, city, category);
}
Console.Beep();
MessageBox.Show("Fertig!");
}
private async Task FetchResults(string requestUri, string stadt, string rubrik)
{
using (HttpClient client = new HttpClient())
{
bool hasNextPage = true;
while (hasNextPage)
{
HttpResponseMessage response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
string jsonResult = await response.Content.ReadAsStringAsync();
JObject result = JObject.Parse(jsonResult);
foreach (var place in result["results"])
{
string placeId = (string)place["place_id"];
string website = await GetPlaceDetails(placeId);
if (!string.IsNullOrEmpty(website))
{
string cleanedUrl = CleanUrl(website);
lstResults.Items.Add(cleanedUrl);
SaveToDatabase(cleanedUrl, stadt, rubrik);
}
}
if (result["next_page_token"] != null)
{
string nextPageToken = (string)result["next_page_token"];
await Task.Delay(2000); // 2 Sekunden warten
requestUri = $"https://maps.googleapis.com/maps/api/place/textsearch/json?pagetoken={nextPageToken}&key={ApiKey}";
}
else
{
hasNextPage = false;
}
}
else
{
MessageBox.Show("Fehler bei der Anfrage: " + response.StatusCode);
hasNextPage = false;
}
}
}
}
private async Task<string> GetPlaceDetails(string placeId)
{
string requestUri = $"https://maps.googleapis.com/maps/api/place/details/json?place_id={placeId}&fields=website&key={ApiKey}";
using (HttpClient client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
string jsonResult = await response.Content.ReadAsStringAsync();
JObject result = JObject.Parse(jsonResult);
return (string)result["result"]["website"];
}
return null;
}
}
private void SaveToDatabase(string website, string stadt, string rubrik)
{
using (MySqlConnection conn = new MySqlConnection(connectionString))
{
conn.Open();
string queryCheck = "SELECT COUNT(*) FROM webCrawler WHERE webseite = @website";
using (MySqlCommand cmdCheck = new MySqlCommand(queryCheck, conn))
{
cmdCheck.Parameters.AddWithValue("@website", website);
int count = Convert.ToInt32(cmdCheck.ExecuteScalar());
if (count == 0)
{
string queryInsert = "INSERT INTO webCrawler (webseite, stadt, rubrik) VALUES (@website, @stadt, @rubrik)";
using (MySqlCommand cmdInsert = new MySqlCommand(queryInsert, conn))
{
cmdInsert.Parameters.AddWithValue("@website", website);
cmdInsert.Parameters.AddWithValue("@stadt", stadt);
cmdInsert.Parameters.AddWithValue("@rubrik", rubrik);
cmdInsert.ExecuteNonQuery();
}
}
}
}
}
public static string CleanUrl(string url)
{
// Entferne das Protokoll (http, https) und 'www.'
Uri uri = new Uri(url);
string host = uri.Host;
// Prüfen, ob "www." am Anfang des Hosts ist und entfernen
if (host.StartsWith("www."))
{
host = host.Substring(4);
}
return host;
}
private List<SearchParam> LoadSearchParamsFromDatabase()
{
var searchParams = new List<SearchParam>();
using (MySqlConnection conn = new MySqlConnection(connectionString))
{
conn.Open();
// Zuerst alle Städte aus der Tabelle Staedte laden
var staedte = new List<string>();
string queryStaedte = "SELECT staedte FROM staedte";
using (MySqlCommand cmdStaedte = new MySqlCommand(queryStaedte, conn))
{
using (MySqlDataReader readerStaedte = cmdStaedte.ExecuteReader())
{
while (readerStaedte.Read())
{
staedte.Add(readerStaedte.GetString("staedte"));
}
}
}
// Dann alle Rubriken aus der Tabelle Rubriken laden
var rubriken = new List<string>();
string queryRubriken = "SELECT rubriken FROM rubriken";
using (MySqlCommand cmdRubriken = new MySqlCommand(queryRubriken, conn))
{
using (MySqlDataReader readerRubriken = cmdRubriken.ExecuteReader())
{
while (readerRubriken.Read())
{
rubriken.Add(readerRubriken.GetString("rubriken"));
}
}
}
// Kombiniere jede Rubrik mit jeder Stadt und füge sie zur Liste hinzu
foreach (var stadt in staedte)
{
foreach (var rubrik in rubriken)
{
searchParams.Add(new SearchParam
{
Rubrik = rubrik,
Stadt = stadt
});
}
}
}
return searchParams;
}
}
public class SearchParam
{
public string Rubrik { get; set; }
public string Stadt { get; set; }
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<ApplicationManifest>app.manifest.xml</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.64" />
<PackageReference Include="MySql.Data" Version="9.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Selenium.WebDriver" Version="4.24.0" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="128.0.6613.11900" />
</ItemGroup>
</Project>